<HTML><HEAD>
  <TITLE>Atari 2600 Specifications</TITLE>
  <META NAME="GENERATOR" CONTENT="nocash XED2HTM converter">
</HEAD><BODY bgcolor="#ffffff" text="#000000" link="#0033cc" vlink="#0033cc" alink="#0033cc">
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="contents"></A><FONT SIZE=+2>&nbsp;Atari 2600 Specifications</FONT></TD></TR></TABLE><BR>
<B>Programming Specifications</B><BR>
<A HREF="#technicaldata">Technical Data</A><BR>
<A HREF="#memoryandiomap">Memory and I/O Map</A><BR>
<A HREF="#video">Video</A><BR>
<A HREF="#intervaltimer">Interval Timer</A><BR>
<A HREF="#audio">Audio</A><BR>
<A HREF="#controllers">Controllers</A><BR>
<A HREF="#cartridges">Cartridges</A><BR>
<A HREF="#cpu65xxmicroprocessor">CPU 65XX Microprocessor</A><BR>
<A HREF="#hardwaresoldering">Hardware / Soldering</A><BR>
<A HREF="#links">Links</A><BR>
<BR>
Writing this documentation simultaneously while US hi-tec machinery was
attacking Bagdad, it must be said that the Atari 2600 was shipped with a
war game called Combat, the Atari 2600's hardware sprites are notably
called "Players", "Missiles", and "Ball". Being manufactured in the cold
war era, the implied purpose of this gaming console is: Playing joyful war
games. War is not a game, war is no fun. War is murder.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="technicaldata"></A><FONT SIZE=+2>&nbsp;Technical Data</FONT></TD></TR></TABLE><BR>
Atari 2600 Video Computer System (VCS)<BR>
Manufacured 1977-1991<BR>
<BR>
<B>Chipset</B><BR>
CPU 6507 - 8bit, 1.19MHz<BR>
TIA 1A - Television Interface Adaptor Model 1A (Video, Audio, Input Ports)<BR>
PIA 6532 - (128 bytes RAM, I/O Ports, Timer)<BR>
<BR>
<B>CPU and Memory</B><BR>
<TABLE><TR><TD><PRE>  CPU:   6507, 8bit, 1.19MHz (cutdown 6502 with only 8K address space)
  RAM:   128 Bytes (additional 128 or 256 bytes in some cartridges)
  VRAM:  None (Picture controlled by I/O Ports only)
  ROM:   External Game Cartridge (usually 2KB or 4KB, or banked 2x4KB)
</TD></TR></TABLE><B>Video</B><BR>
<TABLE><TR><TD><PRE>  Output:      Line-by-line (Registers must be updated each scanline)
  Resolution:  160x192 pixels (NTSC 60Hz), 160x228 pixels (PAL 50Hz)
  Playfield:   40 dots horizontal resolution (rows of 4 pixels per dot)
  Colors:      4 colors at once (one color per object)
  Palette:     128 colors (NTSC), 104 colors (PAL), 8 colors (SECAM)
  Sprites:     2 sprites of 8pix width, 3 sprites of 1pix width
</TD></TR></TABLE><B>Input/Output Ports, Audio, Timer</B><BR>
<TABLE><TR><TD><PRE>  I/O:    Two 8bit I/O ports, six 1bit Input ports
  Timer:  One 8bit Timer (with prescaler; 1,8,64,1024 machine cycles)
  Audio:  Two sound channels (with Frequency, Volume, Noise control)
</TD></TR></TABLE><B>Console Switches</B><BR>
<TABLE><TR><TD><PRE>  Switches: Color/Mono Switch (PAL/NTSC only), and two Difficulty Switches
  Buttons:  Select Button, Reset Button (or Switches in older consoles)
  Hardware: Power Switch, TV Channel Select Switch (not software controlled)
</TD></TR></TABLE><B>Connectors</B><BR>
<TABLE><TR><TD><PRE>  Slot:     One 24 pin Cartridge Slot (with 4K address bus)
  Controls: Two 9 pin Joystick ports (also used for Paddles, Keyboards)
  TV:       One Cinch Socket (Video/Audio TV Signal)
  Power:    9V DC, 500mA (internally converted to 5V DC)
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="memoryandiomap"></A><FONT SIZE=+2>&nbsp;Memory and I/O Map</FONT></TD></TR></TABLE><BR>
<B>Overview</B><BR>
<TABLE><TR><TD><PRE>  0000-002C  TIA Write
  0000-000D  TIA Read (sometimes mirrored at 0030-003D)
  0080-00FF  PIA RAM (128 bytes)
  0280-0297  PIA Ports and Timer
  F000-FFFF  Cartridge Memory (4 Kbytes area)
</TD></TR></TABLE><BR>
Below lists address, name, used bits (ordered 76543210, "1"=used), and
function of all I/O ports and memory. Ports marked as &lt;strobe&gt; are
executing the the specified function when wrinting any data to it (the
written data itself is ignored).<BR>
<BR>
<B>TIA - WRITE ADDRESS SUMMARY (Write only)</B><BR>
<TABLE><TR><TD><PRE>  00      VSYNC   ......1.  vertical sync set-clear
  01      VBLANK  11....1.  vertical blank set-clear
  02      WSYNC   &lt;strobe&gt;  wait for leading edge of horizontal blank
  03      RSYNC   &lt;strobe&gt;  reset horizontal sync counter
  04      NUSIZ0  ..111111  number-size player-missile 0
  05      NUSIZ1  ..111111  number-size player-missile 1
  06      COLUP0  1111111.  color-lum player 0 and missile 0
  07      COLUP1  1111111.  color-lum player 1 and missile 1
  08      COLUPF  1111111.  color-lum playfield and ball
  09      COLUBK  1111111.  color-lum background
  0A      CTRLPF  ..11.111  control playfield ball size & collisions
  0B      REFP0   ....1...  reflect player 0
  0C      REFP1   ....1...  reflect player 1
  0D      PF0     1111....  playfield register byte 0
  0E      PF1     11111111  playfield register byte 1
  0F      PF2     11111111  playfield register byte 2
  10      RESP0   &lt;strobe&gt;  reset player 0
  11      RESP1   &lt;strobe&gt;  reset player 1
  12      RESM0   &lt;strobe&gt;  reset missile 0
  13      RESM1   &lt;strobe&gt;  reset missile 1
  14      RESBL   &lt;strobe&gt;  reset ball
  15      AUDC0   ....1111  audio control 0
  16      AUDC1   ....1111  audio control 1
  17      AUDF0   ...11111  audio frequency 0
  18      AUDF1   ...11111  audio frequency 1
  19      AUDV0   ....1111  audio volume 0
  1A      AUDV1   ....1111  audio volume 1
  1B      GRP0    11111111  graphics player 0
  1C      GRP1    11111111  graphics player 1
  1D      ENAM0   ......1.  graphics (enable) missile 0
  1E      ENAM1   ......1.  graphics (enable) missile 1
  1F      ENABL   ......1.  graphics (enable) ball
  20      HMP0    1111....  horizontal motion player 0
  21      HMP1    1111....  horizontal motion player 1
  22      HMM0    1111....  horizontal motion missile 0
  23      HMM1    1111....  horizontal motion missile 1
  24      HMBL    1111....  horizontal motion ball
  25      VDELP0  .......1  vertical delay player 0
  26      VDELP1  .......1  vertical delay player 1
  27      VDELBL  .......1  vertical delay ball
  28      RESMP0  ......1.  reset missile 0 to player 0
  29      RESMP1  ......1.  reset missile 1 to player 1
  2A      HMOVE   &lt;strobe&gt;  apply horizontal motion
  2B      HMCLR   &lt;strobe&gt;  clear horizontal motion registers
  2C      CXCLR   &lt;strobe&gt;  clear collision latches
</TD></TR></TABLE><B>TIA - READ ADDRESS SUMMARY (Read only)</B><BR>
<TABLE><TR><TD><PRE>  30      CXM0P   11......  read collision M0-P1, M0-P0 (Bit 7,6)
  31      CXM1P   11......  read collision M1-P0, M1-P1
  32      CXP0FB  11......  read collision P0-PF, P0-BL
  33      CXP1FB  11......  read collision P1-PF, P1-BL
  34      CXM0FB  11......  read collision M0-PF, M0-BL
  35      CXM1FB  11......  read collision M1-PF, M1-BL
  36      CXBLPF  1.......  read collision BL-PF, unused
  37      CXPPMM  11......  read collision P0-P1, M0-M1
  38      INPT0   1.......  read pot port
  39      INPT1   1.......  read pot port
  3A      INPT2   1.......  read pot port
  3B      INPT3   1.......  read pot port
  3C      INPT4   1.......  read input
  3D      INPT5   1.......  read input
</TD></TR></TABLE><B>PIA 6532 - RAM, Switches, and Timer (Read/Write)</B><BR>
<TABLE><TR><TD><PRE>  80..FF  RAM     11111111  128 bytes RAM (in PIA chip) for variables and stack
  0280    SWCHA   11111111  Port A; input or output  (read or write)
  0281    SWACNT  11111111  Port A DDR, 0= input, 1=output
  0282    SWCHB   11111111  Port B; console switches (read only)
  0283    SWBCNT  11111111  Port B DDR (hardwired as input)
  0284    INTIM   11111111  Timer output (read only)
  0285    INSTAT  11......  Timer Status (read only, undocumented)
  0294    TIM1T   11111111  set 1 clock interval (838 nsec/interval)
  0295    TIM8T   11111111  set 8 clock interval (6.7 usec/interval)
  0296    TIM64T  11111111  set 64 clock interval (53.6 usec/interval)
  0297    T1024T  11111111  set 1024 clock interval (858.2 usec/interval)
</TD></TR></TABLE><B>Cartridge Memory (4 Kbytes area)</B><BR>
<TABLE><TR><TD><PRE>  F000-FFFF ROM   11111111  Cartridge ROM (4 Kbytes max)
  F000-F07F RAMW  11111111  Cartridge RAM Write (optional 128 bytes)
  F000-F0FF RAMW  11111111  Cartridge RAM Write (optional 256 bytes)
  F080-F0FF RAMR  11111111  Cartridge RAM Read (optional 128 bytes)
  F100-F1FF RAMR  11111111  Cartridge RAM Read (optional 256 bytes)
  003F      BANK  ......11  Cart Bank Switching (for some 8K ROMs, 4x2K)
  FFF4-FFFB BANK  &lt;strobe&gt;  Cart Bank Switching (for ROMs greater 4K)
  FFFC-FFFD ENTRY 11111111  Cart Entrypoint (16bit pointer)
  FFFE-FFFF BREAK 11111111  Cart Breakpoint (16bit pointer)
</TD></TR></TABLE><BR>
See also:<BR>
<A HREF="#memorymirrors">Memory Mirrors</A><BR>
<A HREF="#cartridges">Cartridges</A><BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="memorymirrors"></A><FONT SIZE=+2>&nbsp;Memory Mirrors</FONT></TD></TR></TABLE><BR>
<B>CPU 8K Address Space Mirrors (Step 2000h)</B><BR>
The 6507 CPU is having only 13 address pins (8KBytes, 0000h-1FFFh). All
memory is mirrored in steps of 2000h (ie. at 2000h-3FFFh, 4000h-5FFFh,
and so on, up to E000h-FFFFh). The lower half of each area contains
internal memory (RAM, I/O Ports), the upper half contains external
memory (cartridge ROM or expansion RAM).<BR>
<BR>
<B>TIA Mirrors (Step 10h/40h,100h)</B><BR>
The TIA chip is addressed by A12=0, A7=0. Located in memory at
0000h-007Fh, 0100h-017Fh, 0200h-027Fh, etc., 0F00h-0F7Fh. Output ports
are mirrored twice in each window (at XX00h and XX40h), input port are
mirrored eight times in each window (at XX00h, XX10h, XX20h, XX30h, etc.
XX70h).<BR>
<BR>
<B>PIA RAM Mirrors (Step 100h,400h)</B><BR>
PIA RAM is selected by A12=0, A9=0, A7=1. Located in memory at
0080h-00FFh, 0180h-01FFh, 0480h-04FFh, 0580h-05FFh, etc. The mirror at
0180h is particulary important because it allows the CPU to access RAM
for stack operations.<BR>
<BR>
<B>PIA I/O Mirrors (Step 2h,8h,100h,400h)</B><BR>
PIA I/O is selected by A12=0, A9=1, A7=1. Located in memory at
0280h-02FFh, 0380h-03FFh, 0680h-06FFh, 0780h-07FFh, etc. Each 80h-area
contains 16 mirrors of the PIA I/O ports at XX80h, XX88h, XX90h, XX98h,
etc. And, each 8h-area contains two copies of INTIM (eg. 0284h,0286h)
and INSTAT (eg. 0285h,0287h).<BR>
<BR>
<B>Cartridge Mirrors</B><BR>
Cartridge memory is selected by A12=1. Small 2K cartridges are usually
mirrored twice into the 4K cartridge area. ROM-Bank ports (eg. 1FF8h)
aren't necessarily connected to A12, and may overlap the upper PIA I/O
mirror (eg. 0FF8h).<BR>
<BR>
<B>Note (Commonly used Mirrors)</B><BR>
In some cases, two different ports are located at the same memory
address, one port being Read-only, and the other being Write-only, of
course, there is no physical conflict with such 'overlapping' ports.<BR>
However, human users may prefer to use different memory addresses for
different ports. The following mirrors are used by many games (and in
this document): Timer outputs at 294h-297h (instead of 284h-287h), TIA
inputs at 30h-3Dh (instead of 00h-0Dh).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="video"></A><FONT SIZE=+2>&nbsp;Video</FONT></TD></TR></TABLE><BR>
The display controller operates on a line by line basis, always
outputting the same information every television line unless new data is
written into it by software.<BR>
<BR>
<A HREF="#videosynchronizationandblanking">Video Synchronization and Blanking</A><BR>
<A HREF="#videodimensionsandtimings">Video Dimensions and Timings</A><BR>
<A HREF="#videoplayfield">Video Playfield</A><BR>
<A HREF="#videomobshapeenable">Video MOB Shape/Enable</A><BR>
<A HREF="#videomobhorizontalpositioning">Video MOB Horizontal Positioning</A><BR>
<A HREF="#videomobhorizontalmotion">Video MOB Horizontal Motion</A><BR>
<A HREF="#videocollision">Video Collision</A><BR>
<A HREF="#videocolors">Video Colors</A><BR>
<A HREF="#videopriority">Video Priority</A><BR>
<BR>
"The 5 moveable objects can be positioned anywhere, and consists of 2
players, 2 missiles, and a ball.<BR>
The playfield, players, missiles, and ball are created and manipulated by
a series of registers in the TIA that the microprocessor can address and
write into.<BR>
Each type of object has certain defined capabilities."<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="videosynchronizationandblanking"></A><FONT SIZE=+2>&nbsp;Video Synchronization and Blanking</FONT></TD></TR></TABLE><BR>
<B>00h - VSYNC - Vertical sync set-clear</B><BR>
<TABLE><TR><TD><PRE>  Bit  Expl.
  0    Not used
  1    Vertical Sync            (0=Stop sync, 1=Start sync)
  2-7  Not used
</TD></TR></TABLE>Sync should be output for a duration of 3 scanlines, between the lower and
upper screen border periods.<BR>
<BR>
<B>01h - VBLANK - Vertical blank set-clear</B><BR>
<TABLE><TR><TD><PRE>  Bit  Expl.
  0    Not used
  1    Vertical Blank           (0=Stop blanking, 1=Start blanking)
  2-5  Not used
  6    INPT4-INPT5 Control      (0=Normal Input, 1=Latched Input)
  7    INPT0-INPT3 Control      (0=Normal Input, 1=Dumped to ground)
</TD></TR></TABLE>Note: Disable latches (Bit6=0) also resets latches to logic true.<BR>
The blanking bit should be set for the duration of upper and lower screen
border periods. During blanking, playfield and moveable objects are hidden
and the screen area becomes black.<BR>
<BR>
<B>02h - WSYNC &lt;strobe&gt; - Wait for leading edge of horizontal blank</B><BR>
Writing any value to this address halts microporcessor (by RDY signal)
until end of current scanline, ie. until begin of next H-Blank period.<BR>
Note: Works also in 'hidden' scanlines, ie. during VBlank/VSync.<BR>
<BR>
<B>03h - RSYNC &lt;strobe&gt; - Reset horizontal sync counter</B><BR>
Writing any value to this address resets the horizontal sync counter to<BR>
begin of horizontal blank time (intended for chip testing purposes).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="videodimensionsandtimings"></A><FONT SIZE=+2>&nbsp;Video Dimensions and Timings</FONT></TD></TR></TABLE><BR>
<B>Vertical Timing and Resolution</B><BR>
Vertical sync and blanking must be controlled by software. VBLANK should
be enabled during vsync and upper/lower border periods.<BR>
<TABLE><TR><TD><PRE>  Type_______NTSC__PAL/SECAM______
  V-Sync      3     3    scanlines
  V-Blank     37    45   scanlines (upper border)
  Picture     192   228  scanlines
  Overscan    30    36   scanlines (lower border)
  Frame Rate  60    50   Hz
  Frame Time  262   312  scanlines
</TD></TR></TABLE>Because there is not enough CPU time to change all registers per scanline,
some objects must use a lower vertical resolution than 192 or 228 pixels.<BR>
<BR>
<B>Horizontal Timing and Resolution</B><BR>
Horizontal sync and blanking are done automatically by hardware. The
software may re-synchronize itself to begin of H-Blank by writing to
WSYNC.<BR>
<TABLE><TR><TD><PRE>  Blanking  22.6 machine clocks (68 color clocks)
  Picture   53.3 machine clocks (160 color clocks) (160 pixels)
  Total     76.0 machine clocks (228 color clocks)
</TD></TR></TABLE>The playfield (which takes up the main part of the screen) is restricted
to a horizontal resolution of 40 dots. Moveable objects can be positioned
and drawn at full 160 pixels resolution.<BR>
<BR>
<B>Clocks</B><BR>
<TABLE><TR><TD><PRE>  Video Color Clock: 3.579545 MHz (NTSC), 3.546894 MHz (PAL)
  CPU Machine Clock: 1.193182 MHz (NTSC), 1.182298 MHz (PAL)
</TD></TR></TABLE>The CPU Clock is derived from Video clock divided by three.<BR>
One color clock = 1 pixel. One machine clock = 3 pixels.<BR>
<BR>
Note: For the vertical blanking/overscan periods, it'd be recommended to
program the PIA Timer to blanking time (allowing to execute larger parts
of code without timing synchronization), followed by one WSYNC when the
timer has expired.<BR>
<BR>
Note: Most PAL games increase upper/lower border heights rather than
actually using the full 228 pixels picture height.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="videoplayfield"></A><FONT SIZE=+2>&nbsp;Video Playfield</FONT></TD></TR></TABLE><BR>
Officially, a playfield consists of walls, clouds, barriers, and other
seldom moved objects. In practice, it consists of a 20 bit value, used to
display 20 low resolution dots (rows of 4 pixels per dot). The whole
screen width is 40 dots, the same 20 bit value is used both for the left
and right half (however, the right half may be horizontally mirrored, and,
software may change the PF registers somewhere in the middle of the
scanline).<BR>
<BR>
<B>0Dh - PF0 - Playfield Register 0 (LSB first) (only upper 4bit used)</B><BR>
<B>0Eh - PF1 - Playfield Register 1 (MSB first) (8bit)</B><BR>
<B>0Fh - PF2 - Playfield Register 2 (LSB first) (8bit)</B><BR>
Defines the colors of the separate playfield dots (0=COLUBK, 1=COLUPF).
Depending on the REF bit (CTRLPF.0), the screen output is composed of the
following bits/ordering:<BR>
<TABLE><TR><TD><PRE>  Normal (REF=0) : PF0.4-7 PF1.7-0 PF2.0-7  PF0.4-7 PF1.7-0 PF2.0-7
  Mirror (REF=1) : PF0.4-7 PF1.7-0 PF2.0-7  PF2.7-0 PF1.0-7 PF0.7-4
</TD></TR></TABLE>PF0, PF1, and PF2, should not be written to while the respective register
is currently output to the screen.<BR>
<BR>
<B>0Ah - CTRLPF - Control Playfield and Ball size</B><BR>
<TABLE><TR><TD><PRE>  Bit  Expl.
  0    Playfield Reflection     (0=Normal, 1=Mirror right half)
  1    Playfield Color          (0=Normal, 1=Score Mode, only if Bit2=0)
  2    Playfield/Ball Priority  (0=Normal, 1=Above Players/Missiles)
  3    Not used
  4-5  Ball size                (0..3 = 1,2,4,8 pixels width)
  6-7  Not used
</TD></TR></TABLE>In "score" mode, the playfield is drawn by COLUP0/COLUP1 for left/right
half of screen (instead COLUPF in both halves). Intended to display
2-player mode scores at different colors by low-resolution playfield
graphics (used by older games like Combat).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="videomobshapeenable"></A><FONT SIZE=+2>&nbsp;Video MOB Shape/Enable</FONT></TD></TR></TABLE><BR>
<B>(Ball Size: See CTRLPF)</B><BR>
<BR>
<B>04h - NUSIZ0 - Number-size player-missile 0</B><BR>
<B>05h - NUSIZ1 - Number-size player-missile 1</B><BR>
These addresses control the number and size of players and missiles.<BR>
<TABLE><TR><TD><PRE>  Bit  Expl.
  0-2  Player-Missile number & Player size (See table below)
  3    Not used ???
  4-5  Missile Size  (0..3 = 1,2,4,8 pixels width)
  6-7  Not used
</TD></TR></TABLE>Player-Missile number & player size (Picture shows shape, 8 pix per char)<BR>
<TABLE><TR><TD><PRE>  0  One copy              (X.........)
  1  Two copies - close    (X.X.......)
  2  Two copies - medium   (X...X.....)
  3  Three copies - close  (X.X.X.....)
  4  Two copies - wide     (X.......X.)
  5  Double sized player   (XX........)
  6  Three copies - medium (X...X...X.)
  7  Quad sized player     (XXXX......)
</TD></TR></TABLE>1/2 television line (80 clocks), 8 clocks per character<BR>
<BR>
<B>1Bh - GRP0 - Graphics (enable) player 0</B><BR>
<B>1Ch - GRP1 - Graphics (enable) player 1</B><BR>
<TABLE><TR><TD><PRE>  Bit  Expl.
  0-7  Eight dots player shape   (0=Transparent, 1=Player color)
</TD></TR></TABLE>The dots are usually drawn MSB first (from left to right), but can be
horizontally mirroed by REFP0 and REFP1 registers.<BR>
Use a value of 00h to hide/disable the object.<BR>
<BR>
<B>1Dh - ENAM0 - Graphics (enable) missile 0</B><BR>
<B>1Eh - ENAM1 - Graphics (enable) missile 1</B><BR>
<B>1Fh - ENABL - Graphics (enable) ball</B><BR>
<TABLE><TR><TD><PRE>  Bit  Expl.
  0    Not used
  1    Missile/Ball Enable       (0=Transparent, 1=Missile/Ball color)
  2-7  Not used
</TD></TR></TABLE>The "shape" for these objects consists of a single dot, which may be
horizontally repeated or stretched by NUSIZ/CTRLPF registers.<BR>
Use a value of 00h to hide/disable the object. Missiles can be also hidden
by RESMPx registers (see Positioning chapter).<BR>
<BR>
<B>0Bh - REFP0 - Reflect player 0</B><BR>
<B>0Ch - REFP1 - Reflect player 1</B><BR>
<TABLE><TR><TD><PRE>  Bit  Expl.
  0-2  Not used
  3    Reflect Player Graphics   (0=Normal/MSB first, 1=Mirror/LSB first)
  4-7  Not used
</TD></TR></TABLE>Used to mirror the GRP0 and GRP1 registers.<BR>
<BR>
<B>25h - VDELP0 - Vertical delay player 0 (Delay GRP0 until writing to GRP1)</B><BR>
<B>26h - VDELP1 - Vertical delay player 1 (Delay GRP1 until writing to GRP0)</B><BR>
<B>27h - VDELBL - Vertical delay ball    (Delay ENABL until writing to GRP1)</B><BR>
When VDELPx is set, writes to GRPx are delayed until GRPy is written to -
which may be done in the same scanline, in one of the next scanlines, or
in the next frame, or never - and may thus actually cause a horizontal,
vertical, framerate, or even endless delay.<BR>
<TABLE><TR><TD><PRE>  Bit  Expl.
  0    Vertical Delay  (0=No delay, 1=Delay until writing to GRP0/GRP1)
  1-7  Not used
</TD></TR></TABLE>The misleading name "vertical" delay is used because these registers were
originally intended to be used to update GRPx in one scanline and to have
the changes delayed until GRPy is updated in the next scanline.<BR>
<BR>
<B>Notes on High Resolution Text and Vertical Delay</B><BR>
Many newer games (eg. Pacman) use high resolution text or graphics output,
of 6 characters or 48 pixels width. This is done by configuring NUSIZ to
"three copies close", and positioning GRP0 ("0_0_0") eight pixels to the
left of GRP1 ("1_1_1"), resulting in the pattern "010101".<BR>
Updating GRP0 and GRP1 multiple times within each scanline can be done to
change the pattern to 6 different characters ("012345"), the drawing
procedure requires proper timing, and typically uses "vertical" delay (in
this case behaving as horizontal delay), note that one usually needs 7
writes to GRP registers to draw 6 characters (with one final dummy write
to apply the last (delayed) character).<BR>
The GRPx registers actually consist of two registers each, hereby called
GRPxA (delayed data latch) and GRPxB (actual display data). When VDELx is
disabled, writes to GRPx go directly to GRPxB. When VDELx is enabled,
writes to GRPx go to GRPxA, and GRPxA is copied to GRPxB at the time when
writing to GRPy.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="videomobhorizontalpositioning"></A><FONT SIZE=+2>&nbsp;Video MOB Horizontal Positioning</FONT></TD></TR></TABLE><BR>
<B>10h - RESP0 &lt;strobe&gt; - Reset player 0</B><BR>
<B>11h - RESP1 &lt;strobe&gt; - Reset player 1</B><BR>
<B>12h - RESM0 &lt;strobe&gt; - Reset missile 0</B><BR>
<B>13h - RESM1 &lt;strobe&gt; - Reset missile 1</B><BR>
<B>14h - RESBL &lt;strobe&gt; - Reset ball</B><BR>
Writing any value to these addresses sets the associated objects
horizontal position equal to the current position of the cathode ray beam,
if the write takes place anywhere within horizontal blanking then the
position is set to the left edge of the screen (plus a few pixels towards
right: 3 pixels for P0/P1, and only 2 pixels for M0/M1/BL).<BR>
Note: Because of opcode execution times, it is usually necessary to adjust
the resulting position to the desired value by subsequently using the
Horizontal Motion function.<BR>
<BR>
<B>28h - RESMP0 - Reset missile 0 to player 0</B><BR>
<B>29h - RESMP1 - Reset missile 1 to player 1</B><BR>
<TABLE><TR><TD><PRE>  Bit  Expl.
  0    Not used
  1    Reset Missile to Player  (0=Normal, 1=Hide and Lock on player)
  2-7  Not used
</TD></TR></TABLE>As long as Bit 1 is set, the missile is hidden and its horizontal position
is centered on the players position. The centering offset is +3 for
normal, +6 for double, and +10 quad sized player (that is giving good
centering results with missile widths of 2, 4, and 8 respectively).<BR>
<BR>
<B>Note on Vertical Positioning</B><BR>
None such supported by the video controller. Moveable objects (and
playfield) must be enabled or disabled (or modified in shape) in the
appropriate scanlines by software.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="videomobhorizontalmotion"></A><FONT SIZE=+2>&nbsp;Video MOB Horizontal Motion</FONT></TD></TR></TABLE><BR>
<B>20h - HMP0 - Horizontal motion player 0</B><BR>
<B>21h - HMP1 - Horizontal motion player 1</B><BR>
<B>22h - HMM0 - Horizontal motion missile 0</B><BR>
<B>23h - HMM1 - Horizontal motion missile 1</B><BR>
<B>24h - HMBL - Horizontal motion ball</B><BR>
Specifies the motion direction and step (in pixels). Writing to these
registers does not directly affect the objects position, unless when
subsequently using the HMOVE command.<BR>
<TABLE><TR><TD><PRE>  Bit  Expl.
  0-3  Not used
  4-7  Signed Motion Value (-8..-1=Right, 0=No motion, +1..+7=Left)
</TD></TR></TABLE>Repeatedly writing to HMOVE will repeat the same movement (without having
to rewrite the motion registers).<BR>
<BR>
<B>2Ah - HMOVE &lt;strobe&gt; - Apply horizontal motion</B><BR>
Writing any value to this address applies horizontal motion: The motion
registers (HMP0, HMP1, etc) are added to the position of the moveable
objects (P0, P1, etc):<BR>
<TABLE><TR><TD><PRE>  NewPos = ( OldPos +/- Motion ) MOD 160
</TD></TR></TABLE>Timing Restrictions: The HMOVE command should be used only immediately
after a WSYNC command, this ensures that the operation starts at the
beginning of, and finishes before end of, horizontal blanking (see notes
below). Also, the software should not change any of the motion registers
for at least 24 machine cycles after an HMOVE command.<BR>
<BR>
<B>2Bh - HMCLR &lt;strobe&gt; - Clear horizontal motion registers</B><BR>
Writing any value to this address resets all five motion registers
(HMP0, HMP1, etc) to zero.<BR>
<BR>
<B>HMOVE Extra Blanking</B><BR>
When HMOVE is executed inside of the horizontal blanking period (which
should be usually be so), then the leftmost 8 pixels of the following
scanline are covered by the border color (black).<BR>
That "feature" is probably intended to hide minor dirt effects in moveable
objects while processing motion. The resulting black lines could be
treated as a major dirt effect though (eg. Espial).<BR>
Some games (eg. Hero) issue HMOVEs in all scanlines (so that all scanlines
have masked left pixels, which looks better than only some lines being
masked). Also, the blanking may be of some use with objects that are moved
"half offscreen" (which would usually re-appear at the other side of the
screen).<BR>
Note: Collision checks still take place "below" of the extra blanking area.<BR>
<BR>
<B>HMOVE Extra Motion Offsets</B><BR>
When HMOVE is executed outside of the horizontal blanking period (which
should usually not be done), additional motion offets are added to the
position registers (additonally to the normal HMxx motion values):<BR>
Player Offsets:<BR>
<TABLE><TR><TD><PRE>  6,4,4,2,0           ;-more before blanking, disp RIGHT  \
  -2,-2,-4,-6,-8,-8   ;-area before blanking, disp LEFT   /
  14 dup (0)          ;-blanking area, disp ZERO         |
  2,2,4,6,8,8,10,12   ;-area after blanking, disp RIGHT   \
  8,8,8,8,8...        ;-remaining area, disp FAST RIGHT    ""--__
</TD></TR></TABLE>Missile/Ball Offsets<BR>
<TABLE><TR><TD><PRE>  -1,-2,-2,-3,-4,-5,-5,-6,-7,-8,-8  ;disp LEFT            /
  14 dup (0)          ;-blanking area, disp ZERO         |
  1,1,2,3,4,4,5,6     ;-area after blanking, disp RIGHT   \
  0,0,0,0,0...        ;-remaining area, disp ZERO         |
</TD></TR></TABLE>In such cases, motion may occur even if HMxx registers are all zero.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="videocollision"></A><FONT SIZE=+2>&nbsp;Video Collision</FONT></TD></TR></TABLE><BR>
<B>30h - CXM0P (R)  - Collision Latch M0-P1, M0-P0 (Bit 7,6) (Read only)</B><BR>
<B>31h - CXM1P (R)  - Collision Latch M1-P0, M1-P1 (Bit 7,6) (Read only)</B><BR>
<B>32h - CXP0FB (R) - Collision Latch P0-PF, P0-BL (Bit 7,6) (Read only)</B><BR>
<B>33h - CXP1FB (R) - Collision Latch P1-PF, P1-BL (Bit 7,6) (Read only)</B><BR>
<B>34h - CXM0FB (R) - Collision Latch M0-PF, M0-BL (Bit 7,6) (Read only)</B><BR>
<B>35h - CXM1FB (R) - Collision Latch M1-PF, M1-BL (Bit 7,6) (Read only)</B><BR>
<B>36h - CXBLPF (R) - Collision Latch BL-PF        (Bit 7)   (Read only)</B><BR>
<B>37h - CXPPMM (R) - Collision Latch P0-P1, M0-M1 (Bit 7,6) (Read only)</B><BR>
The TIA detects collisions between any of the 6 objects (the playfield and
5 moveable objects). There are 15 possible two-object collisions which are
stored in 15 one bit latches.<BR>
<TABLE><TR><TD><PRE>  Bit  Expl.
  0-5  Not used
  6,7  Two Collsion Flags   (0=No collision, 1=Collision occured)
</TD></TR></TABLE>The collision registers could be read at any time but is usually done
during vertical blank after all possible collisions have occurred.<BR>
Note: Use CXCLR to reset the collision latches after reading.<BR>
<BR>
<B>2Ch - CXCLR (W) &lt;strobe&gt; - Clear all collision latches</B><BR>
Writing any value to this address resets all collision latches
(CXM0P-CXPPMM) to zero.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="videocolors"></A><FONT SIZE=+2>&nbsp;Video Colors</FONT></TD></TR></TABLE><BR>
See also CTRLPF.1 (SCORE), and SWCHB.3 (B/W)   - and CTRLPF priority<BR>
<BR>
<B>06h - COLUP0 - Color Luminosity Player 0, Missile 0</B><BR>
<B>07h - COLUP1 - Color Luminosity Player 1, Missile 1</B><BR>
<B>08h - COLUPF - Color Luminosity Playfield, Ball</B><BR>
<B>09h - COLUBK - Color Luminosity Background</B><BR>
Selects color and luminance (brightness) for the specified object. The
console can display 128 colors (NTSC), or 104 colors (PAL), or 8 colors
(SECAM) on color TV sets, and 8 grayshades (NTSC/PAL/SECAM) on monochrome
TV sets.<BR>
<TABLE><TR><TD><PRE>  Bit  Expl.
  0    Not used
  1-3  NTSC/PAL Luminance (0-7)  - SECAM: RGB (0-7) - Mono TV: Grayshade (0-7)
  4-7  NTSC/PAL Color     (0-15) - SECAM: Ignored   - Mono TV: Ignored
</TD></TR></TABLE>A smaller luminance value drags the NTSC/PAL colors towards black, a
larger luminance value drags it towards white (pastelized). Software
should process the Color/Mono switch to select between different color
schemes for Color/Mono TV sets (if necessary). PAL Software may choose
luminance values that look okay both on Mono TV sets and on SECAM color TV
sets.<BR>
<BR>
<B>Color & Luminance Values</B><BR>
<TABLE><TR><TD><PRE>  NTSC Colors      PAL Colors         NTSC/PAL Lum.  SECAM RGB
  0 White          0 White            0 Black        0 Black
  1 Gold           1 Same as color 0  1 Dark grey    1 Blue
  2 Orange         2 Yellow           2 ...          2 Red
  3 Bright orange  3 Green-yellow     3 Grey         3 Magenta
  4 Pink           4 Orange           4 ...          4 Green
  5 Purple         5 Green            5 ...          5 Cyan
  6 Purple-blue    6 Pink-orange      6 Light grey   6 Yellow
  7 Blue           7 Green-blue       7 White        7 White
  8 Blue           8 Pink
  9 Light blue     9 Turquois
  A Torq.          A Pink-blue
  B Green-blue     B Light blue
  C Green          C Blue-red
  D Yellow-green   D Dark blue
  E Orange-green   E Same as color 0
  F Light orange   F Same as color 0
</TD></TR></TABLE><BR>
SECAM is a little weird. It takes the PAL software, but the console
color/black & white switch is hardwired as black & white. Therefore, it
reads the PAL black & white tables in software and assigns a fixed color
to each lum of black & white according to the table.<BR>
<BR>
<B>Screen Border Color</B><BR>
The screen border (HBLANK and VBLANK periods) is black.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="videopriority"></A><FONT SIZE=+2>&nbsp;Video Priority</FONT></TD></TR></TABLE><BR>
See also CTRLPF.1 (SCORE), and CTRLPF.2 (PRIORITY)<BR>
<BR>
<B>Object Colors and Priorities</B><BR>
When pixels of two or more objects overlap each other, only the pixel of
the object with topmost priority is drawn to the screen. The normal
priority ordering is:<BR>
<TABLE><TR><TD><PRE>  Priority     Color    Objects
  1 (highest)  COLUP0   P0, M0  (and left side of PF in SCORE-mode)
  2            COLUP1   P1, M1  (and right side of PF in SCORE-mode)
  3            COLUPF   BL, PF  (only BL in SCORE-mode)
  4 (lowest)   COLUBK   BK
</TD></TR></TABLE>Optionally, the playfield and ball may be assigned to have higher
priority (by setting CTRLPF.2). The priority ordering is then:<BR>
<TABLE><TR><TD><PRE>  Priority     Color    Objects
  1 (highest)  COLUPF   PF, BL  (always, the SCORE-bit is ignored)
  2            COLUP0   P0, M0
  3            COLUP1   P1, M1
  4 (lowest)   COLUBK   BK
</TD></TR></TABLE>Objects of the same color are having the same priority (it makes no
difference which pixel is drawn topmost if both pixels are having the
same color).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="intervaltimer"></A><FONT SIZE=+2>&nbsp;Interval Timer</FONT></TD></TR></TABLE><BR>
<B>284h - INTIM - PIA Current Timer Value (Read only)</B><BR>
Reading from this 8bit register returns the current timer value.<BR>
The initial value and interval can be set by TIM1T-T1024T registers.<BR>
<BR>
<B>285h - INSTAT - PIA Timer Status (Read only) (Undocumented)</B><BR>
<TABLE><TR><TD><PRE>  Bit  Expl.
  0-5  Not used           (Seems to be always zero)
  6    Underflow Flag 1   (1=Underflow, since last INSTAT read)
  7    Underflow Flag 2   (1=Underflow, since last TIMnnT write)
</TD></TR></TABLE>Both bit 6 and 7 are set on undeflow. Bit 6 is reset when reading from
INSTAT. Bit 7 is reset when writing to TIM1T..T1024T.<BR>
<BR>
<B>294h - TIM1T - PIA Set Timer & Select 1 clock interval (838ns/interval)</B><BR>
<B>295h - TIM8T - PIA Set Timer & Select 8 clock interval (6.7us/interval)</B><BR>
<B>296h - TIM64T - PIA Set Timer & Select 64 clock interval (53.6us/interval)</B><BR>
<B>297h - T1024T - PIA Set Timer & Select 1024 clock interval (858.2us/interval)</B><BR>
Writing a 8bit value in range of 00h..FFh to any of these four addresses
TIM1T-T1024T sets the timer to that value, and selects the prescaler
interval.<BR>
<BR>
<B>Normal Timer Decrement</B><BR>
The timer is decremented once immediately after writing (ie. value 00h
does immediately underflow). It is then decremented once every N clock
cycle interval (depending on the port address used).<BR>
<BR>
<B>Timer Underflow / Highspeed Decrement</B><BR>
Once when the timer does underflow, it restarts at FFh, and is then
decremented once per clock cycle, regardless of the selected interval
(this feature allows to calculate the exact underflow time at one clock
cycle resolution even if a larger interval was used).<BR>
<BR>
However, the interval is automatically re-actived when reading from the INTIM
register, ie. the timer does then continue to decrement at interval speed
(originated at the current value).<BR>
<BR>
<B>Note</B><BR>
The timer is particulary useful to specify and determine the end of the
vertical blanking periods (upper and lower screen border), allowing to
execute program code during that periods without permanent synchronization
with the cathode ray beam.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="audio"></A><FONT SIZE=+2>&nbsp;Audio</FONT></TD></TR></TABLE><BR>
The TIA chip is having two sound channels which are output, as mono
signal, to the TV set. According to the specs, it can make sounds like a
"flute", a "rocket motor", and an "explosion".<BR>
<BR>
<B>19h - AUDV0 - Audio Volume, Channel 0</B><BR>
<B>1Ah - AUDV1 - Audio Volume, Channel 1</B><BR>
Bit 0-3, Volume 0-15 (0=Off, 15=Loudest)<BR>
Note: The recommended method to disable a sound channel is to set its
volume to zero.<BR>
Does that REALLY FULLY disable sound, or would it be required to be
combined with audc=0 to be fully muted ???<BR>
<BR>
<B>17h - AUDF0 - Audio Frequency Divider, Channel 0</B><BR>
<B>18h - AUDF1 - Audio Frequency Divider, Channel 1</B><BR>
Bit 0-4, Frequency Divider (0..31 = 30KHz/1..30KHz/32)<BR>
The resulting frequency is subsequently divided by AUDC0/AUDC1, which
provides additional division by 2, 6, 31, or 93 for pure tone.<BR>
<TABLE><TR><TD><PRE>  That is, based on 3.58MHz/128 or 1.19MHz/40 or scanline*2 or else ???
  "PAL Sounds will drop a little in pitch (frequency) because of a slower
  crystal clock. Some sounds may need the AUDF0/AUDF1 touched up."
  Other clock? Same for SECAM? What rate? Really? I thought video
  timing is raw software controlled? PAL=3.54MHz only ???
</TD></TR></TABLE><BR>
<B>15h - AUDC0 - Audio Noise/Division Control, Channel 0</B><BR>
<B>16h - AUDC1 - Audio Noise/Division Control, Channel 1</B><BR>
<TABLE><TR><TD><PRE>    These registers control nine bit shift counters, and may select
    different shift counter feedback taps and count lengths to produce
    a variety of noise and tone qualities.
</TD></TR></TABLE>Bit 0-3, Noise/Division Control (0-15, see below)<BR>
<TABLE><TR><TD><PRE>  0  set to 1                    8  9 bit poly (white noise)
  1  4 bit poly                  9  5 bit poly
  2  div 15 -&gt; 4 bit poly        A  div 31 : pure tone
  3  5 bit poly -&gt; 4 bit poly    B  set last 4 bits to 1
  4  div 2 : pure tone           C  div 6 : pure tone
  5  div 2 : pure tone           D  div 6 : pure tone
  6  div 31 : pure tone          E  div 93 : pure tone
  7  5 bit poly -&gt; div 2         F  5 bit poly div 6
</TD></TR></TABLE>A setting of zero will disable the sound (PAL/NTSC), or it will produce an
"obnoxious background sound" (SECAM).<BR>
<BR>
<B>AUDC Pattern Shapes</B><BR>
<TABLE><TR><TD><PRE>  x Rep Pattern Shape
  0   1 ----------------------------------------------------------------------
  1  15 ----___-__--_-_----___-__--_-_----___-__--_-_----___-__--_-_----___-__
  2 465 --------------------------------------------------------------________
  3 465 ------______-___---__-----___-------___----___--__--_____---------___-
  4   2 -_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
  5   2 -_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
  6  31 ------------------_____________------------------_____________--------
  7  31 -----___--_---_-_-____-__-_--__-----___--_---_-_-____-__-_--__-----___
  8 511 ---------_____----_-----___-_---__--__-_____-__-_-__---_--_-___----__-
  9  31 -----___--_---_-_-____-__-_--__-----___--_---_-_-____-__-_--__-----___
  A  31 ------------------_____________------------------_____________--------
  B   1 ----------------------------------------------------------------------
  C   6 ---___---___---___---___---___---___---___---___---___---___---___---_
  D   6 ---___---___---___---___---___---___---___---___---___---___---___---_
  E  93 -------------------------------------------------_____________________
  F  93 ----------_____---_______----__________------___------____---------___
</TD></TR></TABLE><BR>
<B>AUDC Pattern Type Notes</B><BR>
Types 1,8,9 produce 4bit,9bit,5bit poly sound (see Formulas below).<BR>
Type 7 produces exactly the same sound as Type 9 (the additional "div2" is
eventually meant to use div2 transitions as clock, which is identical as
normal 1 cycle clock).<BR>
Type 2 fetches next 4bit poly (type 1) on each div31 (type 6) transition,
the duration of each Poly4 bit is thus multiplied by 18 or by 13.<BR>
Type 3 uses the most complicated mechanism (for reverse engineering). The
Poly5 operation takes place each cycle. If Poly5-Carry is 1, then the 4bit
poly operation is executed and the Poly4-Carry is output to the sound
channel, otherwise Poly4 (and sound output) are kept unchanged.<BR>
Types 4,5 both produce div2 tone, consisting of 1 HIGH and 1 LOW cycle.<BR>
Types 6,A both produce div31 tone, consisting of 18 HIGH and 13 LOW cycles
(that odd numbers are eventually based on 5bit poly being applied only
when lower 4bits all same, maybe).<BR>
Types 0,B both produce a permanent HIGH signal and the sound is
effectively disabled (at least with PAL/NTSC, however SECAM produces
"obnoxious background sound" in this case).<BR>
Types C,D,E,F are using same mechanism as types 4,5,6,7 but only each 3rd
transition is applied.<BR>
<BR>
<B>Internal Poly Formulas</B><BR>
Poly/Noise is generated by shift/xor operations. The rightmost bit of the
shift register is output to the sound channel (0=low, 1=high). The
register is shifted right and the new leftmost bit is calculated by an XOR
operation:<BR>
<TABLE><TR><TD><PRE>  poly  old bits   output  new bits   calculation
  4bit  abcd       d       zabc       z = c xor d
  5bit  abcde      e       zabcd      z = c xor e
  9bit  abcdefghi  i       zabcdefgh  z = e xor i
</TD></TR></TABLE><BR>
<B>Internal Poly Bitstreams</B><BR>
Below are example bitstreams, the rightmost bit is output to the sound
channel, the two x-marked bits are XORed by each other and used as new
leftmost bit in next cycle. The dots "..." indicate frozen poly4 settings.<BR>
<TABLE><TR><TD><PRE>  4bit    5bit     9bit poly    5bit-&gt;4bit
 ---xx-  ---x-x-  -----x---x-  ---x-x---xx-
  1111    11111    111111111    10011 1111
  0111    01111    011111111    11001 0111
  0011    00111    001111111    11100 ...1
  0001    00011    000111111    11110 ...1
  1000    10001    000011111    11111 0011
  0100    11000    000001111    01111 0001
  0010    01100    100000111    00111 1000
  1001    10110    110000011    00011 0100
  1100    11011    111000001    10001 0010
  0110    11101    111100000    11000 ...0
  1011    01110    011110000    01100 ...0
  0101    10111    101111000    10110 ...0
  1010    01011    110111100    11011 1001
  1101    10101    111011110    11101 1100
  1110    01010    111101111    01110 ...0
  1111    00101    111110111    10111 0110
  0111    00010    011111011    01011 1011
  0011    00001    001111101    10101 0101
  0001    10000    000111110    01010 ...1
  1000    01000    100011111    00101 1010
  0100    00100    010001111    00010 ...0
  0010    10010    101000111    00001 1101
  1001    01001    110100011    10000 ...1
  1100    10100    111010001    01000 ...1
  0110    11010    011101000    00100 ...1
  1011    01101    001110100    10010 ...1
  0101    00110    100111010    01001 1110
  1010    10011    110011101    10100 ...0
  1101    11001    011001110    11010 ...0
  1110    11100    001100111    01101 1111
  1111    11110    100110011    00110 ...1
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="controllers"></A><FONT SIZE=+2>&nbsp;Controllers</FONT></TD></TR></TABLE><BR>
<B>Specific Controller Types</B><BR>
<A HREF="#controllersjoysticks">Controllers: Joysticks</A><BR>
<A HREF="#controllerspaddles">Controllers: Paddles</A><BR>
<A HREF="#controllerskeypad">Controllers: Keypad</A><BR>
<A HREF="#controllerssteering">Controllers: Steering</A><BR>
<A HREF="#controllersother">Controllers: Other</A><BR>
<BR>
<B>Basic Tech Info</B><BR>
<A HREF="#controllersconsoleswitches">Controllers: Console Switches</A><BR>
<A HREF="#controllersioregisters">Controllers: I/O Registers</A><BR>
<A HREF="#controllersexternalportpinouts">Controllers: External Port Pin-Outs</A><BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="controllersjoysticks"></A><FONT SIZE=+2>&nbsp;Controllers: Joysticks</FONT></TD></TR></TABLE><BR>
Joysticks are the most common controllers. Two joysticks can be connected.<BR>
<BR>
<B>Normal 4-Direction / 1-Button Joysticks</B><BR>
Configure Port A as input (SWACNT=00h). Joystick data can be then read
from SWCHA and INPT4-5 as follows:<BR>
<TABLE><TR><TD><PRE>  Pin  PlayerP0  PlayerP1  Expl.
  1    SWCHA.4   SWCHA.0   Up     (0=Moved, 1=Not moved)
  2    SWCHA.5   SWCHA.1   Down   ("")
  3    SWCHA.6   SWCHA.2   Left   ("")
  4    SWCHA.7   SWCHA.3   Right  ("")
  6    INPT4.7   INPT5.7   Button (0=Pressed, 1=Not pressed)
</TD></TR></TABLE>Note: Connect all direction switches and push buttons to GND (Pin 8).<BR>
<BR>
<B>3-Button Joystick Adapter</B><BR>
The device fits on the shaft of standard Atari joysticks, it includes two
additional buttons, and is connected by separate cable between the normal
joystick plug and consoles joystick port.<BR>
The device comes up without any external pullup/pulldown resistors, it acts
somewhat similar than leftmost/rightmost paddle positions and must deal with
the capacitors/resistors inside of the console (see Paddles chapter for
details).<BR>
In general, software must drag INPT0-3 to ground for a moment (eg. during
vertical blanking period):<BR>
<TABLE><TR><TD><PRE>  Pin  Bit       Expl.
  5,9  VBLANK.7  INPT0-INPT3 Control   (0=Normal Input, 1=Dumped to ground)
</TD></TR></TABLE>Software must then wait a moment (eg. until end of picture drawing period)
before it can read the adapters button states:<BR>
<TABLE><TR><TD><PRE>  Pin  PlayerP0  PlayerP1  Expl.
  5    INPT0.7   INPT2.7   2nd Button  (1=Pressed/Charged)
  9    INPT1.7   INPT3.7   3rd Button  (1=Pressed/Charged)
</TD></TR></TABLE>Note: Connect the extra buttons to VCC (Pin 7).<BR>
The 3-button adapter is used by Omega Race and Thrust (both games aren't
actually using all 3 buttons for 3 unique purposes though).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="controllerspaddles"></A><FONT SIZE=+2>&nbsp;Controllers: Paddles</FONT></TD></TR></TABLE><BR>
A paddle consists of single knob (similar like the volume control of HiFi
amplifiers), and a single push button. Two paddles can be connected to
each port (four paddles can be used when using both ports). Paddles are
usually shipped as pair of two controllers which are attached (by Y-cable)
to a single plug.<BR>
<BR>
To read paddle buttons, configure SWCHA as input (SWACNT=00h), then read
from SWCHA:<BR>
<TABLE><TR><TD><PRE>  Pin  Bit       Expl.
  3    SWCHA.2   Paddle #3  button (right paddle, P1) (0=Pressed)
  4    SWCHA.3   Paddle #2  button (left paddle, P1)
  3    SWCHA.6   Paddle #1  button (right paddle, P0)
  4    SWCHA.7   Paddle #0  button (left paddle, P0)
</TD></TR></TABLE>To read paddle pots, switch INPT0-3 to LOW by setting VBLANK.7, this
discharges the 68nF capacitors (inside of the console), then reset
VBLANK.7 again, the capacitors are now charged through linear 1M Ohm
potentiometers in the paddle (in series with 1.8K Ohm resistors in the
console).<BR>
<TABLE><TR><TD><PRE>  Pin  Bit       Expl.
  5,9  VBLANK.7  INPT0-INPT3 Control  (0=Normal Input, 1=Dumped to ground)
</TD></TR></TABLE>Then measure the time it takes until INPTx pins are getting high:<BR>
<TABLE><TR><TD><PRE>  Pin  Bit       Expl.
  9    INPT3.7   Paddle #3  pot    (right paddle, P1) (1=Charged/Ready)
  5    INPT2.7   Paddle #2  pot    (left paddle, P1)
  9    INPT1.7   Paddle #1  pot    (right paddle, P0)
  5    INPT0.7   Paddle #0  pot    (left paddle, P0)
</TD></TR></TABLE>Note: Connect buttons to GND (Pin 8), pots to VCC (Pin 7), leave 3rd pot
pin not connected.<BR>
<BR>
<B>POT Timing Table (counted in scanline units)</B><BR>
Analogue timings are, of course, unstable. Expect the scanline count to
vary by at least +/-1 even if the POT is not moved. Counter range may vary
with different hardware, depending on accuracy/tolerance of the components
in the paddle and in the console, and on the room temperature. Also,
larger counter values may be measured when the circuit has warmed up
(after some minutes of operation).<BR>
<TABLE><TR><TD><PRE>  Position   Left &lt;--------- Center ---------&gt; Right
  Degrees    -135   -90   -45   0   +45   +90   +135
  Ohms       1M     ...   ...  500K  ...   ...     0
  Scanlines  380    ...   ...  190   ...   ...     0
</TD></TR></TABLE>Note that it may take two or more frames until the maximum count is
reached, ideally, software should check INPTs throughout drawing and
blanking periods, and carry on in the next frame. Implement a timeout
after 1000 scanlines (to prevent the software getting hung, and/or to
detect the presence of paddles).<BR>
<BR>
According to AtariAge FAQ, paddles are used by 31 games: Astroblast
(joystick ok too), Bachelor Party, Backgammon, Beat Em' & Eat Em,
Blackjack, Breakout (Breakaway IV), Bugs, Bumper Bash, Canyon Bomber,
Casino (Poker Plus), Circus Atari (Circus), Demons to Diamonds,
Eggomania, Encounter at L-5, Fireball, Guardian, Kaboom!, Music Machine,
Night Driver, Party Mix, Picnic, Piece O Cake, Solar Storm, Star Wars:
Jedi Arena, Steeplechase, Street Racer (Speedway II), Super Breakout,
Tac-Scan, Video Olympics (Pong Sports), Warlords, Warplock.<BR>
Also by "actionmn.bin" ???<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="controllerskeypad"></A><FONT SIZE=+2>&nbsp;Controllers: Keypad</FONT></TD></TR></TABLE><BR>
The keypad or touchpad controller has 12 buttons arranged into 4 rows and
3 columns. The names "0..9,#,*" are printed directly on the controller.
Aside from this predefined names, software is usually shipped with
overlays: small cards (with holes for the keys) with custom names or
symbols printed on the card. The Basic Programming cartridge uses two
(separate) keypads with 24 keys in total.<BR>
<BR>
To access the keypad, configure SWCHA as output (SWACNT=FFh), then select
a row by writing to SWCHA, then wait 400us, then read column bits from
INPTx registers.<BR>
<TABLE><TR><TD><PRE>  Pin  PlayerP0   PlayerP1   Expl.                      Keys
  1    SWCHA.4    SWCHA.0    Upper row     (0=Select)   1,2,3
  2    SWCHA.5    SWCHA.1    Second row    (0=Select)   4,5,6
  3    SWCHA.6    SWCHA.2    Third row     (0=Select)   7,8,9
  4    SWCHA.7    SWCHA.3    Bottom row    (0=Select)   *,0,#
  5    INPT0.7    INPT2.7    Left column   (0=Pressed)  1,4,7,*
  9    INPT1.7    INPT3.7    Middle column (0=Pressed)  2,5,8,0
  6    INPT4.7    INPT5.7    Right column  (0=Pressed)  3,6,9,#
</TD></TR></TABLE>Note: Pin 9 and 5 require external 4.7K Ohm pullups to pin 7.<BR>
<BR>
According to AtariAge FAQ, kid's controllers/keypads are used by 11
games: A Game of Concentration (Hunt & Score Memory Match), Alpha Beam
with Ernie, BASIC Programming, Big Bird's Egg Catch, Brain Games,
Codebreaker, Cookie Monster Munch, Grover's Music Maker (prototype),
MagiCard, Oscar's Trash Race, Star Raiders.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="controllerssteering"></A><FONT SIZE=+2>&nbsp;Controllers: Steering</FONT></TD></TR></TABLE><BR>
Which 2600 games use the driving controllers?<BR>
<TABLE><TR><TD><PRE>  Indy 500 and
  Stell-A-Sketch (homebrew program)
</TD></TR></TABLE>The device looks about exactly like a paddle, using a knob as steering
'wheel', and a push button. Unlike paddles, only one device can be
connected to each game port (ie. no Y-cable pairs). Also unlike paddles,
the knob is attached to a 16 position rotary binary switch, which allows
endless rotation (ie. by more than 360 degrees).<BR>
Even though the 16 position switch provides 4 bit combinations, only 2
bits are connected, the output starts over at zero once every four
positions.<BR>
Configure Port A as input (SWACNT=00h). Steering data can be then read
from SWCHA and INPT4-5 as follows:<BR>
<TABLE><TR><TD><PRE>  Pin  PlayerP0  PlayerP1  Expl.
  1    SWCHA.4   SWCHA.0   Pos    (0=Closed, 1=Not closed)
  2    SWCHA.5   SWCHA.1   Pos    ("")
  6    INPT4.7   INPT5.7   Button (0=Pressed, 1=Not pressed)
</TD></TR></TABLE>Note: Connect switch and push buttons to GND (Pin 8).<BR>
<BR>
16 Position Real Code Binary Rotary DIP-Switch:<BR>
<TABLE><TR><TD><PRE>   ________
  |   BIT1 |____________________ Pin 1 (Up)
  |   BIT2 |__      |__ ____
  |   BIT3 |__         |XOR \___ Pin 2 (Down)
  |   BIT0 |___________|____/
  | Rotary |        |__     ____ Pin 7 (Vcc)
  |  DIP   |           [10K]
  | Switch |____________________ Pin 8 (Gnd)
  |    GND |        |  Button
  |________|        |___o--o____ Pin 6 (Button)
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="controllersother"></A><FONT SIZE=+2>&nbsp;Controllers: Other</FONT></TD></TR></TABLE><BR>
Which games use a lightgun?<BR>
<TABLE><TR><TD><PRE>  Sentinel
  Shooting Arcade (prototype only)
</TD></TR></TABLE><BR>
Trackball<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="controllersconsoleswitches"></A><FONT SIZE=+2>&nbsp;Controllers: Console Switches</FONT></TD></TR></TABLE><BR>
Aside from external controllers, the console includes five built-in
switches or buttons.<BR>
<BR>
<B>Accessing Console Switches</B><BR>
Configure Port B as input (SWBCNT=00h). Switch/Button data can be then
read from SWCHB as follows:<BR>
<TABLE><TR><TD><PRE>  Bit        Expl.
  SWCHB.0    Reset Button          (0=Pressed)
  SWCHB.1    Select Button         (0=Pressed)
  SWCHB.2    Not used
  SWCHB.3    Color Switch          (0=B/W, 1=Color) (Always 0 for SECAM)
  SWCHB.4-5  Not used
  SWCHB.6    P0 Difficulty Switch  (0=Beginner (B), 1=Advanced (A))
  SWCHB.7    P1 Difficulty Switch  (0=Beginner (B), 1=Advanced (A))
</TD></TR></TABLE>Note: Older consoles used switches instead of buttons for reset/select.<BR>
SECAM consoles do not include a color switch (Bit 3 is grounded).<BR>
<BR>
<B>Software Switches/Buttons</B><BR>
Above buttons/switches may (or may not) be used by software for whatever
purpose. Namely, the Reset Button does not reset any hardware, and the
Color Switch does not have any effect on the video output (unless the
software processes it as such).<BR>
<BR>
<B>Hardware Switches</B><BR>
On the contrary, the Power Switch and TV Channel Select Switch cannot be
processed by software.<BR>
<BR>
<B>Data Direction Register (SWBCNT)</B><BR>
Port B is hardwired to console switches (inputs), normally SWBCNT should
be always 00h. However, the three unused bits could be configured as
output, the respective SWCHB bits can be then used to store 3bits of
custom read/writeable data (as done by Combat).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="controllersioregisters"></A><FONT SIZE=+2>&nbsp;Controllers: I/O Registers</FONT></TD></TR></TABLE><BR>
<B>38h - INPT0 (R) - 1....... TIA Dumped Input Port 1 (Pot 1)</B><BR>
<B>39h - INPT1 (R) - 1....... TIA Dumped Input Port 2 (Pot 2)</B><BR>
<B>3Ah - INPT2 (R) - 1....... TIA Dumped Input Port 3 (Pot 3)</B><BR>
<B>3Bh - INPT3 (R) - 1....... TIA Dumped Input Port 4 (Pot 4)</B><BR>
As long as bit 7 of register VBLANK is zero, these four ports are
general purpose high impedance input ports. When this bit is a 1 these
ports are grounded.<BR>
INPT0-3 can be used to read up to four paddle controllers, and, INPT0-1
can be used to read Keyboard columns 0 and 1.<BR>
<BR>
<B>3Ch - INPT4 (R) - 1.......  TIA Latched Input Port 4</B><BR>
<B>3Dh - INPT5 (R) - 1.......  TIA Latched Input Port 5</B><BR>
These two ports have latches that are both enabled by writing a "1" or
disabled by writing a "0" to D6 of VBLANK.<BR>
When disabled, the microprocessor reads the logic level of the port
directly.<BR>
When enabled, the latch is set for logic one and remains that way until
its port goes LOW (not sure what happens if it was already LOW ???).
When the port goes LOW the latch goes LOW and remains that way (until
re-disabled by VBLANK Bit 6) regardless of what the port does.<BR>
<BR>
<B>280h - SWCHA - PIA Port A; input or output (R/W)</B><BR>
<TABLE><TR><TD><PRE>  Bit  Expl.
  0-7  Data Inputs or Outputs (Direction depends on SWACNT)
</TD></TR></TABLE>Used to access various types of external controllers (joysticks, paddles,
or keyboard, etc.).<BR>
<BR>
<B>281h - SWACNT - PIA Port A DDR Data Direction Register (R/W)</B><BR>
<TABLE><TR><TD><PRE>  Bit  Expl.
  0-7  Data Direction for SWCHA Bit 0-7   (0=Input, 1=Output)
</TD></TR></TABLE>Use value 00h for joysticks and paddles. Use FFh for keypad.<BR>
<BR>
<B>282h - SWCHB - PIA Port B, Console Switches (R/W) (normally Read Only)</B><BR>
<TABLE><TR><TD><PRE>  Bit  Expl.
  0-7  Data Inputs or Outputs (Direction depends on SWBCNT)
</TD></TR></TABLE>Used to read console switches/buttons.<BR>
<BR>
<B>283h - SWBCNT - PIA Port B DDR Data Direction Register (R/W)</B><BR>
<TABLE><TR><TD><PRE>  Bit  Expl.
  0-7  Data Direction for SWCHB Bit 0-7   (0=Input, 1=Output)
</TD></TR></TABLE>Should be always 00h for reading buttons or switches.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="controllersexternalportpinouts"></A><FONT SIZE=+2>&nbsp;Controllers: External Port Pin-Outs</FONT></TD></TR></TABLE><BR>
<B>Joystick Ports (two ports, male 9pin SUBD each)</B><BR>
<TABLE><TR><TD><PRE>  Pin Port 1  Port 2   Joystick  Paddles   Keyboard  +-------------+
  1   SWCHA.4 SWACH.0  Up        -         Row 0      \ 1 2 3 4 5 /
  2   SWCHA.5 SWACH.1  Down      -         Row 1       \ 6 7 8 9 /
  3   SWCHA.6 SWCHA.2  Left      Button 1  Row 2        +-------+
  4   SWCHA.7 SWCHA.3  Right     Button 0  Row 3
  5   INPT0   INPT2    -         Pot 0     Column 0
  6   INPT4   INPT5    Button    -         Column 2
  7   +5V     +5V      -         VCC/Pot   Pull-ups
  8   GND     GND      GND       GND/Butt  -
  9   INPT1   INPT3    -         Pot 1     Column 1
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="cartridges"></A><FONT SIZE=+2>&nbsp;Cartridges</FONT></TD></TR></TABLE><BR>
<A HREF="#cartrawromunbanked">Cart Raw ROM (unbanked)</A><BR>
<A HREF="#cart4kbankingbyportffxxh">Cart 4K-Banking (by Port FFxxh)</A><BR>
<A HREF="#cart2kbankingbyportffxxh">Cart 2K-Banking (by Port FFxxh)</A><BR>
<A HREF="#cart1kbankingbyportffxxh">Cart 1K-Banking (by Port FFxxh)</A><BR>
<A HREF="#cart2kbankingbyport3fh">Cart 2K-Banking (by Port 3Fh)</A><BR>
<A HREF="#cart4kbankingbyjsrrtsopcodes">Cart 4K-Banking (by JSR/RTS opcodes)</A><BR>
<A HREF="#cartpitfall2">Cart Pitfall 2</A><BR>
<A HREF="#cartexpansionram">Cart Expansion RAM</A><BR>
<A HREF="#cartpinouts">Cart Pin-Outs</A><BR>
<A HREF="#cartsummaryandgeneralinfo">Cart Summary and General Info</A><BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="cartrawromunbanked"></A><FONT SIZE=+2>&nbsp;Cart Raw ROM (unbanked)</FONT></TD></TR></TABLE><BR>
<B>4K and 2K ROMs</B><BR>
Cartridges of 4KBytes fit directly into the 4K cartridge area.<BR>
Cartridges of 2KBytes are mirrored twice in the 4K cartridge area.<BR>
<BR>
<B>Smaller ROMs</B><BR>
Cartridges of 1KByte size haven't been manufactured, however, some
homebrewn games may or may not use that filesize. A strange example is
"Cave 1K", which is actually "2K", because it inserts 1024 bytes padding
between (!) the program code and the reset vector (eventually intended for
compatibility with software that accepts only 2K rom-images as minimum
filesize).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="cart4kbankingbyportffxxh"></A><FONT SIZE=+2>&nbsp;Cart 4K-Banking (by Port FFxxh)</FONT></TD></TR></TABLE><BR>
The bank number is selected by reading from (or by writing any value to)
specific addresses, the addresses and corresponding bank numbers are:<BR>
<TABLE><TR><TD><PRE>  Size   Banks  FFF4 FFF5 FFF6 FFF7 FFF8 FFF9 FFFA FFFB
  2K,4K  1      -    -    -    -    -    -    -    -
  8K     2      -    -    -    -    0    1    -    -
  12K    3      -    -    -    -    0    1    2    -
  16K    4      -    -    0    1    2    3    -    -
  32K    8      0    1    2    3    4    5    6    7
</TD></TR></TABLE>Banks are usually selected by "BIT FFFx" opcodes, after execution of
such opcodes the program counter is PC=PC+3, the new bank must contain
valid code at that address (that is usually implemented by placing code
at fixed addresses at the beginning or end of each ROM bank).<BR>
The initial bank number is undefined upon power-on, so each bank should
contain a valid entry point at [FFFC], and a small power-on procedure.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="cart2kbankingbyportffxxh"></A><FONT SIZE=+2>&nbsp;Cart 2K-Banking (by Port FFxxh)</FONT></TD></TR></TABLE><BR>
burgtime,he_man: eight 2K banks (16K)<BR>
also used by bnj (but first 8K empty, only upper 8K used)<BR>
<TABLE><TR><TD><PRE>  FFE0-FFE7 bank 0-7 for F000-F7FF
  FFE8 used by burgtime ONLY, don't know, initialize something ???
  expansion RAM at F800-F9FF
  bank 7 fixed at FA00-FFFF
</TD></TR></TABLE><BR>
The game BNJ consists of four 2K banks. Bank 3 is permanently mapped to
F800-FFFF, and either bank 0,1,2 can be mapped to F000-F7FF, selected by
accessing FFE4,FFE5,FFE6. Note: For whatever reason, the Bnj.bin
rom-image at AtariAge is 16K, the first 8K are empty, the other 8K
contain bank 0-3. (NB. this obscure file format allows to detect
2K-banking.)<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="cart1kbankingbyportffxxh"></A><FONT SIZE=+2>&nbsp;Cart 1K-Banking (by Port FFxxh)</FONT></TD></TR></TABLE><BR>
<B>Memory Addresses for 8x1K (8K) Banking</B><BR>
<TABLE><TR><TD><PRE>  FFE0-FFE7 bank 0-7 for F000-F3FF
  FFE8-FFEF bank 0-7 for F400-F7FF
  FFF0-FFF7 bank 0-7 for F800-FBFF
  bank 7 fixed       at  FC00-FFFF
</TD></TR></TABLE>Used by: Popeye, Gyruss, Sprcobra, Tutank, Dethstar, Qbrtcube, Ewokadvn,
Montzrev, Frogger2, Lordofth, James_bo, Swarcade, Toothpro.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="cart2kbankingbyport3fh"></A><FONT SIZE=+2>&nbsp;Cart 2K-Banking (by Port 3Fh)</FONT></TD></TR></TABLE><BR>
<B>Memory Addresses for Port 3Fh 4x2K (8K) Banking</B><BR>
<TABLE><TR><TD><PRE>  MOV [3F],n     bank 0-2 for F000-F7FF
  bank 3 fixed            at  F800-FFFF
</TD></TR></TABLE>Used by: Springer, Espial, Minrvol2, Mnr2049r, Riverp, Polaris.<BR>
<BR>
this port is NOT to be mirrored to [7F] - mnr2049r zerofills 40..FF memory<BR>
on power-on must be initially BANK 3 (polaris entrypt=7000, mirror of 7800)<BR>
access normal TIA ports only by mirrors at 40h-7Fh!<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="cart4kbankingbyjsrrtsopcodes"></A><FONT SIZE=+2>&nbsp;Cart 4K-Banking (by JSR/RTS opcodes)</FONT></TD></TR></TABLE><BR>
JSR/RTS for banking (2x4K) (8K)<BR>
<TABLE><TR><TD><PRE>  bank1 select by CALL DXXX opcode,
  bank0 select by RET FXXX opcode
</TD></TR></TABLE>Used by Decathln only.<BR>
<BR>
does not use any PUSH/POP, banking done by STACK accesses, probably only
if SP.Bit0 is set (or cleared)<BR>
detect by clearmem-loop at F000, followed by call D000 opcode<BR>
entrypoint in bank0 only!<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="cartpitfall2"></A><FONT SIZE=+2>&nbsp;Cart Pitfall 2</FONT></TD></TR></TABLE><BR>
The Pitfall 2 cartridge includes eight counters. (Five sequential
video/data channels with automatically decrementing pointers, and one
3-channel audio/data generator). The program can read from the channels
and can then write the data directly to the TIA ports (without having to
adjust pointers/counters by software).<BR>
<BR>
<B>Cartridge I/O Map</B><BR>
<TABLE><TR><TD><PRE>  Channel   Data  Mask   Max/y1 Min/y2 Lsb   Msb
  ch0 video 1008  1010   1040   1048   1050  1058
  ch1 video 1009  -      -      -      1051  1059
  ch2 video 100A  -      -      -      1052  105A
  ch3 video 100B  1013   1043   104B   1053  105B
  ch4 video 100C  -      -      -      1054  105C
  ch5 audio /--\  -      1045   104D   1055  105D
  ch6 audio 1006  -      1046   104E   1056  105E
  ch7 audio \--/  -      1047   104F   1057  105F
  poly8     1000  -      -      -      -     -
  bank 0    1FF8  -      -      -      -     -
  bank 1    1FF9  -      -      -      -     -
</TD></TR></TABLE>Addresses 1000h-103Fh read only, 1040h and up write only.<BR>
Area 1000h-107Fh (and 1800h-187Fh) in ROM should be not used (FFh filled).<BR>
<BR>
<B>Display Data Channels</B><BR>
The first 5 channels are used to retrieve video data. The LSB and MSB
registers contain a 11bit counter (the upper 5bit are unused?), used to
address data in the 2K ROM area.<BR>
Normal data access: Reading from the DATA register returns the addressed
byte and does automatically decrement the counter. Intended for general
purpose display data (GRP0,PF0,COLUP0,etc.).<BR>
Masked data access: Reading from the MASK register works in the same way
as above, but the returned data is forced to 00h if the channels output is
disabled. The output is initially disabled (when writing to
MIN/MAX/LSB/MSB?), output gets enabled when LSB=MAX, and gets disabled
when LSB=MIN. Intended for vertical positioning of moveable objects (eg.
hiding GRP0 in unused lines by forcing GRP0=00h).<BR>
(Pitfall2 program code uses masked access only for channel 0 and 3, not
sure if other channels can use that feature as well?)<BR>
<BR>
<B>Audio Data Channels</B><BR>
The other 3 channels are used to generate 3 channel square? wave audio
data. The LSB registers are 8bit counters automatically decremented at ca.
30kHz rate (or other speed?) (by external oscillator?), upon underflow,
LSB is automatically reset to MAX?, the wave output is switched high when
LSB=MAX, and low when LSB=MIN. For audio, the MSB serves as control
register rather than as counter? MSB Bit5 seems to enable the channel. MSB
Bit4 does something/what: volume, length, noise, else? Other MSB Bits
unused?<BR>
The output levels of the 3 channels are automatically added? together,
probably high=5, low=0?, and can be read from Port 1006h, intended to be
forwarded to AUDV0, with AUDC0=0 (always high), preferably at least once
per scanline. The AUDx1 registers can be used as normal, as fourth sound
channel.<BR>
<BR>
<B>ROM and Poly8</B><BR>
The first 8K (2000h) of the Pitfall ROM image contain normal program
code/data, using normal 4K Port 1FF8h/1FF9h bank switching. The next 2K
(800h) contain sequential data, used by channel 0-4, apparently in
reversed order (in rom-image and/or real rom?), ie. addressed by "NOT
counter". Finally, 255 bytes (FFh) of 8bit poly data are somewhat attached
to the Pitfall2 ROM-images being found in internet (resulting in the
obscure filesize of 28FFh bytes).<BR>
In reality, the poly data is likely to be generated by shift register, and
probably not stored in a ROM? The poly data is used for what purpose?
Audio? Not at all? Or Port 1000h? Pitfall reads from Port 1000h once every
4 frames, Bit 7 of the returned data seems to be used only? as color code
for the blinking electric eels? If so, does one really need external
hardware to produce blinking colors? The next poly value is generated
when: at fixed rate or after reading from any or specific register?<BR>
The poly stream can be produced by taking the parity of Bits 7,5,4,3 of
the current value, the new value is then shifted left, with the old parity
(1=even) shifted in to Bit 0. Example: 00, 01, 03, 07, 0F, 1E, 3D, 7A, F4,
E8, D0, A1, 43, 87, 0E, 1C, etc. The stream restarts each 255 cycles.<BR>
<BR>
All info (and all question marks) gained from examining the pitfall2
rom-image, but without having viewed/listened/debugged the original
cartridge.<BR>
<BR>
<B>NB.</B><BR>
When I first heard of the cartridge, having been wondering how it'd work,
my first bet was to write a value of FFh to [TIA+mirror], allowing the
cartridge to drag the databus to (FFh AND data). That method would take up
only 3 cycles per write (instead 4+3 per read+write as actually used in
pitfall2), and using different mirror address could be used for different
channels. Not sure if it'd work stable, and if it'd be of any use to
create games with higher video resolution, or for any other features.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="cartexpansionram"></A><FONT SIZE=+2>&nbsp;Cart Expansion RAM</FONT></TD></TR></TABLE><BR>
<B>Expansion RAM</B><BR>
Some cartridges include additional 128 bytes (or 256 bytes) of external
RAM, that memory is NOT (???) battery buffered. Because the cartridge
slot does not include a read/write signal, different memory addresses
must be used for reading and writing, mapped as such:<BR>
<TABLE><TR><TD><PRE>  Cart Type      4K-Banking 4K-Banking 2K-Banking
  RAM Size       128 bytes  256 bytes  256 bytes
  RAM Write Area F000-F07F  F000-F0FF  F800-F8FF
  RAM Read Area  F080-F0FF  F100-F1FF  F900-F9FF
  ROM Size       3.75K      3.5K       1.5K
  ROM Area       F100-FFFF  F200-FFFF  FA00-FFFF
</TD></TR></TABLE>The first 256 bytes (or 512 bytes) of each ROM bank are unused, these
areas should be 00h or FFh filled in ROM-images. (NB. That allows to
determine if a game uses external RAM. Omegarace and Digdug use garbage
filled area though.)<BR>
RAM can be accessed from inside of all ROM-banks (but it is always the
same 128 or 256 bytes of RAM, ie. RAM is NOT banked).<BR>
Note: Attempts to read from Write Addresses would overwrite the
addressed byte by garbage. Thus, external RAM cannot be used by
read-and-write opcodes (ie. INC, DEC, ASL, LSR, ROL, and ROR).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="cartpinouts"></A><FONT SIZE=+2>&nbsp;Cart Pin-Outs</FONT></TD></TR></TABLE><BR>
<B>Cartridge Slot (24 pins)</B><BR>
The A12 pin is used as CS (chip select, active HIGH), this works okay
with the type of ROMs used in original cartridges. Standard EPROMs are
expecting /CS though (active LOW), so that EPROM cartridges must include an
inverter (transistor circuit, or 7404 chip, or similar).<BR>
<TABLE><TR><TD><PRE>  +--------------------------------------------------+
  |                                                  |
  | /EX +5V  A8  A9  A11 A10 A12 D7  D6  D5  D4  D3  |
  |  A7  A6  A5  A4  A3  A2  A1  A0  D0  D1  D2  GND |
  +--------------------------------------------------+
</TD></TR></TABLE>The /EXROM pin should be connected to GND inside of the cartridge, it
isn't actually used, but it would allow the console to detect if a
cartridge is inserted.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="cartsummaryandgeneralinfo"></A><FONT SIZE=+2>&nbsp;Cart Summary and General Info</FONT></TD></TR></TABLE><BR>
<B>Available ROM and Expansion RAM Sizes</B><BR>
<TABLE><TR><TD><PRE>  ROM Type:Port RAM  Used by how many games
  1K   -        -    1   (Cave1k - when removing 2K-padding)
  2K   -        -    51
  4K   -        -    296
  8K   2x4K     -    111
  8K   2x4K     128  3   (Stargate,Defendr2,Elevator)
  8K   2x4K:JSR -    1   (Decathln)
  8K   4x2K:3Fh -    6   (Springer,Espial,Minrvol2,Mnr2049r,Riverp,Polaris)
  8K   4x2K     256  1   (Bnj - when removing 16K padding)
  8K   8x1K     -    13
  10K  2x4K+2K  -    1   (Pitfall2, with sequential data channels)
  12K  3x4K     256  3   (Mtnking,Omegarac,Tunlrunr)
  16K  4x4K     -    31
  16K  4x4K     128  13
  16K  8x2K     -    2   (Burgtime,He_man)
  32K  8x4K     128  1   (Fatalrun)
</TD></TR></TABLE>AtariAge collection, 533 games in total.<BR>
<BR>
<B>ROM Origin & Entrypoint</B><BR>
ROM is usually originated at F000h, there are no headers or checksums
required, only the Entrypoint (and Breakpoint, if using the BRK opcode)
vectors are required to be located at following addresses:<BR>
<TABLE><TR><TD><PRE>  FFFC-FFFD   CPU Entrypoint (16bit pointer)
  FFFE-FFFF   CPU Breakpoint (16bit pointer)
</TD></TR></TABLE>That is, these addresses must contain a 16bit pointer (data), which
points to the actual reset/break procedures (code). For small 2K ROMs,
addresses FFFXh are mirrors of F7FXh.<BR>
<BR>
<B>Bank Switching</B><BR>
ROMs bigger than 4KBytes are split into several banks of 4KBytes each,
and must include a small circuit that latches the current bank number.<BR>
<BR>
<B>Cartridge Mirrors</B><BR>
The 4K cartridge area is addressed by A12 signal, causing it to be
mirrored to all addresses with Bit 12 set, 1000h, 3000h, 5000h, etc. (2K
ROMs also to 1800h, 3800h, 5800h, etc.)<BR>
Most 2K and 4K programs are originated at F000h. Larger ROMS are often
using different addresses for each bank - for example, bank 0 at D000h,
and bank 1 at F000h (mainly to make .MAP files more obvious).<BR>
<BR>
<B>File Extension</B><BR>
The most common extension for Atart 2600 ROM-Images is ".bin".<BR>
Reportedly, some PAL games use ".pal". Also, some games use ".a26".<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="cpu65xxmicroprocessor"></A><FONT SIZE=+2>&nbsp;CPU 65XX Microprocessor</FONT></TD></TR></TABLE><BR>
<B>Overview</B><BR>
<A HREF="#cpuregistersandflags">CPU Registers and Flags</A><BR>
<A HREF="#cpumemoryaddressing">CPU Memory Addressing</A><BR>
<BR>
<B>Instruction Set</B><BR>
<A HREF="#cpumemoryandregistertransfers">CPU Memory and Register Transfers</A><BR>
<A HREF="#cpuarithmeticlogicaloperations">CPU Arithmetic/Logical Operations</A><BR>
<A HREF="#cpurotateandshiftinstructions">CPU Rotate and Shift Instructions</A><BR>
<A HREF="#cpujumpandcontrolinstructions">CPU Jump and Control Instructions</A><BR>
<A HREF="#cpuillegalopcodes">CPU Illegal Opcodes</A><BR>
<BR>
<B>Other Info</B><BR>
<A HREF="#cpuassemblerdirectivessyntax">CPU Assembler Directives/Syntax</A><BR>
<A HREF="#cpuglitches">CPU Glitches</A><BR>
<A HREF="#cputhe65xxfamily">CPU The 65XX Family</A><BR>
<A HREF="#cpulocalusage">CPU Local Usage</A><BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="cpuregistersandflags"></A><FONT SIZE=+2>&nbsp;CPU Registers and Flags</FONT></TD></TR></TABLE><BR>
The 65XX CPUs are equipped with not more than three 8bit general purpose
registers (A, X, Y). However, the limited number of registers (and
complete lack of 16bit registers other than PC) is parts of covered by
comfortable memory operations, especially page 0 of memory (address
0000h-00FFh) may be used for relative fast and complicated operations,
in so far one might say that the CPU has about 256 8bit 'registers' (or
128 16bit 'registers') in memory. For details see Memory Addressing
chapter.<BR>
<BR>
<B>Registers</B><BR>
<TABLE><TR><TD><PRE>  Bits Name  Expl.
  8    A     Accumulator
  8    X     Index Register X
  8    Y     Index Register Y
  16   PC    Program Counter
  8    S     Stack Pointer (see below)
  8    P     Processor Status Register (see below)
</TD></TR></TABLE><BR>
<B>Stack Pointer</B><BR>
The stack pointer is addressing 256 bytes in page 1 of memory, ie.
values 00h-FFh will address memory at 0100h-01FFh. As for most other
CPUs, the stack pointer is decrementing when storing data. However, in
the 65XX world, it points to the first FREE byte on stack, so, when
initializing stack to top set S=(1)FFh (rather than S=(2)00h).<BR>
<BR>
<B>Processor Status Register (Flags)</B><BR>
<TABLE><TR><TD><PRE>  Bit  Name  Expl.
  0    C     Carry         (0=No Carry, 1=Carry)
  1    Z     Zero          (0=Nonzero, 1=Zero)
  2    I     IRQ Disable   (0=IRQ Enable, 1=IRQ Disable)
  3    D     Decimal Mode  (0=Normal, 1=BCD Mode for ADC/SBC opcodes)
  4    B     Break Flag    (0=IRQ/NMI, 1=BRK/PHP opcode)
  5    -     Not used      (Always 1)
  6    V     Overflow      (0=No Overflow, 1=Overflow)
  7    N     Negative/Sign (0=Positive, 1=Negative)
</TD></TR></TABLE><BR>
<B>Carry Flag (C)</B><BR>
Caution: When used for subtractions (SBC and CMP), the carry flag is
having opposite meaning as for normal 80x86 and Z80 CPUs, ie. it is SET
when above-or-equal. For all other instructions (ADC, ASL, LSR, ROL,
ROR) it works as normal, whereas ROL/ROR are rotating &lt;through&gt; carry
(ie. much like 80x86 RCL/RCR and not like ROL/ROR).<BR>
<BR>
<B>Zero Flag (Z), Negative/Sign Flag (N), Overflow Flag (V)</B><BR>
Works just as everywhere, Z it is set when result (or destination
register, in case of some 'move' instructions) is zero, N is set when
signed (ie. same as Bit 7 of result/destination). V is set when an
addition/subtraction exceeded the maximum range for signed numbers
(-128..+127).<BR>
<BR>
<B>IRQ Disable Flag (I)</B><BR>
Disables IRQs when set. NMIs (non maskable interrupts) and BRK
instructions cannot be disabled.<BR>
<BR>
<B>Decimal Mode Flag (D)</B><BR>
Packed BCD mode (range 00h..99h) for ADC and SBC opcodes.<BR>
<BR>
<B>Break Flag (B)</B><BR>
The Break flag is intended to separate between IRQ and BRK which are both
using the same vector, [FFFEh]. The flag cannot be accessed directly, but
there are 4 situations which are writing the P register to stack, which
are then allowing the examine the B-bit in the pushed value: The BRK and
PHP opcodes always write "1" into the bit, IRQ/NMI execution always write
"0".<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="cpumemoryaddressing"></A><FONT SIZE=+2>&nbsp;CPU Memory Addressing</FONT></TD></TR></TABLE><BR>
<B>Opcode Addressing Modes</B><BR>
<TABLE><TR><TD><PRE>  Name           Native   Nocash
  Implied        -        A,X,Y,S,P
  Immediate      #nn      nn
  Zero Page      nn       [nn]
  Zero Page,X    nn,X     [nn+X]
  Zero Page,Y    nn,Y     [nn+Y]
  Absolute       nnnn     [nnnn]
  Absolute,X     nnnn,X   [nnnn+X]
  Absolute,Y     nnnn,Y   [nnnn+Y]
  (Indirect,X)   (nn,X)   [[nn+X]]
  (Indirect),Y   (nn),Y   [[nn]+Y]
</TD></TR></TABLE><BR>
<B>Zero Page - [nn] [nn+X] [nn+Y]</B><BR>
Uses an 8bit parameter (one byte) to address the first 256 of memory at
0000h..00FFh. This limited range is used even for "nn+X" and "nn+Y", ie.
"C0h+60h" will access 0020h (not 0120h).<BR>
<BR>
<B>Absolute - [nnnn] [nnnn+X] [nnnn+Y]</B><BR>
Uses a 16bit parameter (two bytes) to address the whole 64K of memory at
0000h..FFFFh. Because of the additional parameter bytes, this is a bit slower
than Zero Page accesses.<BR>
<BR>
<B>Indirect - [[nn+X]] [[nn]+Y]</B><BR>
Uses an 8bit parameter that points to a 16bit parameter in page zero.<BR>
Even though the CPU doesn't support 16bit registers (except for the program
counter), this (double-)indirect addressing mode allows to use variable 16bit
pointers.<BR>
<BR>
<B>On-Chip Bi-directional I/O port</B><BR>
Addresses (00)00h and (00)01h are occupied by an I/O port which is built-in
into 6510, 8500, 7501, 8501 CPUs (eg. used in C64 and C16), be sure not to
use the addresses as normal memory. For description read chapter about I/O
ports.<BR>
<BR>
<B>Caution</B><BR>
Because of the identical format, assemblers will be more or less unable
to separate between [XXh+r] and [00XXh+r], the assembler will most
likely produce [XXh+r] when address is already known to be located in
page 0, and [00XXh+r] in case of forward references.<BR>
Beside for different opcode size/time, [XXh+r] will always access page 0
memory (even when XXh+r&gt;FFh), while [00XXh+r] may direct to memory in
page 0 or 1, to avoid unpredictable results be sure not to use
(00)XXh+r&gt;FFh if possible.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="cpumemoryandregistertransfers"></A><FONT SIZE=+2>&nbsp;CPU Memory and Register Transfers</FONT></TD></TR></TABLE><BR>
<B>Register to Register Transfer</B><BR>
<TABLE><TR><TD><PRE>  A8        nz----  2   TAY         Transfer Accumulator to Y    Y=A
  AA        nz----  2   TAX         Transfer Accumulator to X    X=A
  BA        nz----  2   TSX         Transfer Stack pointer to X  X=S
  98        nz----  2   TYA         Transfer Y to Accumulator    A=Y
  8A        nz----  2   TXA         Transfer X to Accumulator    A=X
  9A        ------  2   TXS         Transfer X to Stack pointer  S=X
</TD></TR></TABLE>Nocash syntax: MOV dest,source (eg. MOV Y,A = TAY).<BR>
<BR>
<B>Load Register from Memory</B><BR>
<TABLE><TR><TD><PRE>  A9 nn     nz----  2   LDA #nn     Load A with Immediate     A=nn
  A5 nn     nz----  3   LDA nn      Load A with Zero Page     A=[nn]
  B5 nn     nz----  4   LDA nn,X    Load A with Zero Page,X   A=[nn+X]
  AD nn nn  nz----  4   LDA nnnn    Load A with Absolute      A=[nnnn]
  BD nn nn  nz----  4*  LDA nnnn,X  Load A with Absolute,X    A=[nnnn+X]
  B9 nn nn  nz----  4*  LDA nnnn,Y  Load A with Absolute,Y    A=[nnnn+Y]
  A1 nn     nz----  6   LDA (nn,X)  Load A with (Indirect,X)  A=[WORD[nn+X]]
  B1 nn     nz----  5*  LDA (nn),Y  Load A with (Indirect),Y  A=[WORD[nn]+Y]
  A2 nn     nz----  2   LDX #nn     Load X with Immediate     X=nn
  A6 nn     nz----  3   LDX nn      Load X with Zero Page     X=[nn]
  B6 nn     nz----  4   LDX nn,Y    Load X with Zero Page,Y   X=[nn+Y]
  AE nn nn  nz----  4   LDX nnnn    Load X with Absolute      X=[nnnn]
  BE nn nn  nz----  4*  LDX nnnn,Y  Load X with Absolute,Y    X=[nnnn+Y]
  A0 nn     nz----  2   LDY #nn     Load Y with Immediate     Y=nn
  A4 nn     nz----  3   LDY nn      Load Y with Zero Page     Y=[nn]
  B4 nn     nz----  4   LDY nn,X    Load Y with Zero Page,X   Y=[nn+X]
  AC nn nn  nz----  4   LDY nnnn    Load Y with Absolute      Y=[nnnn]
  BC nn nn  nz----  4*  LDY nnnn,X  Load Y with Absolute,X    Y=[nnnn+X]
</TD></TR></TABLE>* Add one cycle if indexing crosses a page boundary.<BR>
Nocash syntax: MOV reg,op (MOV Y,12h; MOV X,[12h+Y]; MOV A,[[NN]+Y]; etc.)<BR>
<BR>
<B>Store Register in Memory</B><BR>
<TABLE><TR><TD><PRE>  85 nn     ------  3   STA nn      Store A in Zero Page     [nn]=A
  95 nn     ------  4   STA nn,X    Store A in Zero Page,X   [nn+X]=A
  8D nn nn  ------  4   STA nnnn    Store A in Absolute      [nnnn]=A
  9D nn nn  ------  5   STA nnnn,X  Store A in Absolute,X    [nnnn+X]=A
  99 nn nn  ------  5   STA nnnn,Y  Store A in Absolute,Y    [nnnn+Y]=A
  81 nn     ------  6   STA (nn,X)  Store A in (Indirect,X)  [[nn+x]]=A
  91 nn     ------  6   STA (nn),Y  Store A in (Indirect),Y  [[nn]+y]=A
  86 nn     ------  3   STX nn      Store X in Zero Page     [nn]=X
  96 nn     ------  4   STX nn,Y    Store X in Zero Page,Y   [nn+Y]=X
  8E nn nn  ------  4   STX nnnn    Store X in Absolute      [nnnn]=X
  84 nn     ------  3   STY nn      Store Y in Zero Page     [nn]=Y
  94 nn     ------  4   STY nn,X    Store Y in Zero Page,X   [nn+X]=Y
  8C nn nn  ------  4   STY nnnn    Store Y in Absolute      [nnnn]=Y
</TD></TR></TABLE>Nocash syntax: MOV op,reg (MOV [12h],A; MOV [12h+Y],X; MOV [[NN]+Y],A; etc.)<BR>
<BR>
<B>Push/Pull</B><BR>
<TABLE><TR><TD><PRE>  48        ------  3   PHA         Push accumulator on stack        [S]=A
  08        ------  3   PHP         Push processor status on stack   [S]=P
  68        nz----  4   PLA         Pull accumulator from stack      A=[S]
  28        nzcidv  4   PLP         Pull processor status from stack P=[S]
</TD></TR></TABLE>Notes: PLA sets Z and N according to content of A. The B-flag and unused
flags cannot be changed by PLP, these flags are always written as "1" by PHP.<BR>
Nocash syntax: PUSH A; PUSH P; POP A; POP P.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="cpuarithmeticlogicaloperations"></A><FONT SIZE=+2>&nbsp;CPU Arithmetic/Logical Operations</FONT></TD></TR></TABLE><BR>
<B>Add memory to accumulator with carry</B><BR>
<TABLE><TR><TD><PRE>  69 nn     nzc--v  2   ADC #nn     Add Immediate           A=A+C+nn
  65 nn     nzc--v  3   ADC nn      Add Zero Page           A=A+C+[nn]
  75 nn     nzc--v  4   ADC nn,X    Add Zero Page,X         A=A+C+[nn+X]
  6D nn nn  nzc--v  4   ADC nnnn    Add Absolute            A=A+C+[nnnn]
  7D nn nn  nzc--v  4*  ADC nnnn,X  Add Absolute,X          A=A+C+[nnnn+X]
  79 nn nn  nzc--v  4*  ADC nnnn,Y  Add Absolute,Y          A=A+C+[nnnn+Y]
  61 nn     nzc--v  6   ADC (nn,X)  Add (Indirect,X)        A=A+C+[[nn+X]]
  71 nn     nzc--v  5*  ADC (nn),Y  Add (Indirect),Y        A=A+C+[[nn]+Y]
</TD></TR></TABLE>* Add one cycle if indexing crosses a page boundary.<BR>
Nocash syntax: ADC A,op (ADC A,12h; ADC A,[12h+X]; ADC A,[[NN]+Y]; etc.)<BR>
<BR>
<B>Subtract memory from accumulator with borrow</B><BR>
<TABLE><TR><TD><PRE>  E9 nn     nzc--v  2   SBC #nn     Subtract Immediate      A=A+C-1-nn
  E5 nn     nzc--v  3   SBC nn      Subtract Zero Page      A=A+C-1-[nn]
  F5 nn     nzc--v  4   SBC nn,X    Subtract Zero Page,X    A=A+C-1-[nn+X]
  ED nn nn  nzc--v  4   SBC nnnn    Subtract Absolute       A=A+C-1-[nnnn]
  FD nn nn  nzc--v  4*  SBC nnnn,X  Subtract Absolute,X     A=A+C-1-[nnnn+X]
  F9 nn nn  nzc--v  4*  SBC nnnn,Y  Subtract Absolute,Y     A=A+C-1-[nnnn+Y]
  E1 nn     nzc--v  6   SBC (nn,X)  Subtract (Indirect,X)   A=A+C-1-[[nn+X]]
  F1 nn     nzc--v  5*  SBC (nn),Y  Subtract (Indirect),Y   A=A+C-1-[[nn]+Y]
</TD></TR></TABLE>* Add one cycle if indexing crosses a page boundary.<BR>
Nocash syntax: SBC A,op (SBC A,12h; SBC A,[12h+X]; SBC A,[[NN]+Y]; etc.)<BR>
Note: Compared with normal 80x86 and Z80 CPUs, incoming and resulting
Carry Flag are reversed.<BR>
<BR>
<B>Logical AND memory with accumulator</B><BR>
<TABLE><TR><TD><PRE>  29 nn     nz----  2   AND #nn     AND Immediate      A=A AND nn
  25 nn     nz----  3   AND nn      AND Zero Page      A=A AND [nn]
  35 nn     nz----  4   AND nn,X    AND Zero Page,X    A=A AND [nn+X]
  2D nn nn  nz----  4   AND nnnn    AND Absolute       A=A AND [nnnn]
  3D nn nn  nz----  4*  AND nnnn,X  AND Absolute,X     A=A AND [nnnn+X]
  39 nn nn  nz----  4*  AND nnnn,Y  AND Absolute,Y     A=A AND [nnnn+Y]
  21 nn     nz----  6   AND (nn,X)  AND (Indirect,X)   A=A AND [[nn+X]]
  31 nn     nz----  5*  AND (nn),Y  AND (Indirect),Y   A=A AND [[nn]+Y]
</TD></TR></TABLE>Nocash syntax: AND A,op (AND A,12h; AND A,[12h+X]; AND A,[[NN]+Y]; etc.)<BR>
* Add one cycle if indexing crosses a page boundary.<BR>
<BR>
<B>Exclusive-OR memory with accumulator</B><BR>
<TABLE><TR><TD><PRE>  49 nn     nz----  2   EOR #nn     XOR Immediate      A=A XOR nn
  45 nn     nz----  3   EOR nn      XOR Zero Page      A=A XOR [nn]
  55 nn     nz----  4   EOR nn,X    XOR Zero Page,X    A=A XOR [nn+X]
  4D nn nn  nz----  4   EOR nnnn    XOR Absolute       A=A XOR [nnnn]
  5D nn nn  nz----  4*  EOR nnnn,X  XOR Absolute,X     A=A XOR [nnnn+X]
  59 nn nn  nz----  4*  EOR nnnn,Y  XOR Absolute,Y     A=A XOR [nnnn+Y]
  41 nn     nz----  6   EOR (nn,X)  XOR (Indirect,X)   A=A XOR [[nn+X]]
  51 nn     nz----  5*  EOR (nn),Y  XOR (Indirect),Y   A=A XOR [[nn]+Y]
</TD></TR></TABLE>Nocash syntax: XOR A,op (XOR A,12h; XOR A,[12h+X]; XOR A,[[NN]+Y]; etc.)<BR>
* Add one cycle if indexing crosses a page boundary.<BR>
<BR>
<B>Logical OR memory with accumulator</B><BR>
<TABLE><TR><TD><PRE>  09 nn     nz----  2   ORA #nn     OR Immediate       A=A OR nn
  05 nn     nz----  3   ORA nn      OR Zero Page       A=A OR [nn]
  15 nn     nz----  4   ORA nn,X    OR Zero Page,X     A=A OR [nn+X]
  0D nn nn  nz----  4   ORA nnnn    OR Absolute        A=A OR [nnnn]
  1D nn nn  nz----  4*  ORA nnnn,X  OR Absolute,X      A=A OR [nnnn+X]
  19 nn nn  nz----  4*  ORA nnnn,Y  OR Absolute,Y      A=A OR [nnnn+Y]
  01 nn     nz----  6   ORA (nn,X)  OR (Indirect,X)    A=A OR [[nn+X]]
  11 nn     nz----  5*  ORA (nn),Y  OR (Indirect),Y    A=A OR [[nn]+Y]
</TD></TR></TABLE>Nocash syntax: OR A,op (OR A,12h; OR A,[12h+X]; OR A,[[NN]+Y]; etc.)<BR>
* Add one cycle if indexing crosses a page boundary.<BR>
<BR>
<B>Compare</B><BR>
<TABLE><TR><TD><PRE>  C9 nn     nzc---  2   CMP #nn     Compare A with Immediate     A-nn
  C5 nn     nzc---  3   CMP nn      Compare A with Zero Page     A-[nn]
  D5 nn     nzc---  4   CMP nn,X    Compare A with Zero Page,X   A-[nn+X]
  CD nn nn  nzc---  4   CMP nnnn    Compare A with Absolute      A-[nnnn]
  DD nn nn  nzc---  4*  CMP nnnn,X  Compare A with Absolute,X    A-[nnnn+X]
  D9 nn nn  nzc---  4*  CMP nnnn,Y  Compare A with Absolute,Y    A-[nnnn+Y]
  C1 nn     nzc---  6   CMP (nn,X)  Compare A with (Indirect,X)  A-[[nn+X]]
  D1 nn     nzc---  5*  CMP (nn),Y  Compare A with (Indirect),Y  A-[[nn]+Y]
  E0 nn     nzc---  2   CPX #nn     Compare X with Immediate     X-nn
  E4 nn     nzc---  3   CPX nn      Compare X with Zero Page     X-[nn]
  EC nn nn  nzc---  4   CPX nnnn    Compare X with Absolute      X-[nnnn]
  C0 nn     nzc---  2   CPY #nn     Compare Y with Immediate     Y-nn
  C4 nn     nzc---  3   CPY nn      Compare Y with Zero Page     Y-[nn]
  CC nn nn  nzc---  4   CPY nnnn    Compare Y with Absolute      Y-[nnnn]
</TD></TR></TABLE>* Add one cycle if indexing crosses a page boundary.<BR>
Nocash syntax: CMP reg,op (CMP X,12h; CMP A,[12h+X]; CMP A,[[NN]+Y]; etc.)<BR>
Note: Compared with normal 80x86 and Z80 CPUs, resulting Carry Flag is
reversed.<BR>
<BR>
<B>Bit Test</B><BR>
<TABLE><TR><TD><PRE>  24 nn     xz---x  3   BIT nn      Bit Test   A AND [nn], N=[nn].7, V=[nn].6
  2C nn nn  xz---x  4   BIT nnnn    Bit Test   A AND [..], N=[..].7, V=[..].6
</TD></TR></TABLE>Nocash syntax: TEST A,op (TEST A,[12h]; TEST A,[1234h]; etc.)<BR>
<BR>
<B>Increment by one</B><BR>
<TABLE><TR><TD><PRE>  E6 nn     nz----  5   INC nn      Increment Zero Page    [nn]=[nn]+1
  F6 nn     nz----  6   INC nn,X    Increment Zero Page,X  [nn+X]=[nn+X]+1
  EE nn nn  nz----  6   INC nnnn    Increment Absolute     [nnnn]=[nnnn]+1
  FE nn nn  nz----  7   INC nnnn,X  Increment Absolute,X   [nnnn+X]=[nnnn+X]+1
  E8        nz----  2   INX         Increment X            X=X+1
  C8        nz----  2   INY         Increment Y            Y=Y+1
</TD></TR></TABLE>Nocash syntax: INC op/reg (INC [12h]; INC [1234h+X]; INC Y; etc.)<BR>
<BR>
<B>Decrement by one</B><BR>
<TABLE><TR><TD><PRE>  C6 nn     nz----  5   DEC nn      Decrement Zero Page    [nn]=[nn]-1
  D6 nn     nz----  6   DEC nn,X    Decrement Zero Page,X  [nn+X]=[nn+X]-1
  CE nn nn  nz----  6   DEC nnnn    Decrement Absolute     [nnnn]=[nnnn]-1
  DE nn nn  nz----  7   DEC nnnn,X  Decrement Absolute,X   [nnnn+X]=[nnnn+X]-1
  CA        nz----  2   DEX         Decrement X            X=X-1
  88        nz----  2   DEY         Decrement Y            Y=Y-1
</TD></TR></TABLE>Nocash syntax: DEC op/reg (DEC [12h]; DEC [1234h+X]; DEC Y; etc.)<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="cpurotateandshiftinstructions"></A><FONT SIZE=+2>&nbsp;CPU Rotate and Shift Instructions</FONT></TD></TR></TABLE><BR>
<B>Shift Left</B><BR>
<TABLE><TR><TD><PRE>  0A        nzc---  2   ASL A       Shift Left Accumulator   SHL A
  06 nn     nzc---  5   ASL nn      Shift Left Zero Page     SHL [nn]
  16 nn     nzc---  6   ASL nn,X    Shift Left Zero Page,X   SHL [nn+X]
  0E nn nn  nzc---  6   ASL nnnn    Shift Left Absolute      SHL [nnnn]
  1E nn nn  nzc---  7   ASL nnnn,X  Shift Left Absolute,X    SHL [nnnn+X]
</TD></TR></TABLE>Nocash syntax: SHL op/reg (SHL A; SHL [12h]; SHL [1234h+X]; etc.)<BR>
<BR>
<B>Shift Right</B><BR>
<TABLE><TR><TD><PRE>  4A        0zc---  2   LSR A       Shift Right Accumulator  SHR A
  46 nn     0zc---  5   LSR nn      Shift Right Zero Page    SHR [nn]
  56 nn     0zc---  6   LSR nn,X    Shift Right Zero Page,X  SHR [nn+X]
  4E nn nn  0zc---  6   LSR nnnn    Shift Right Absolute     SHR [nnnn]
  5E nn nn  0zc---  7   LSR nnnn,X  Shift Right Absolute,X   SHR [nnnn+X]
</TD></TR></TABLE>Nocash syntax: SHR op/reg (SHR A; SHR [12h]; SHR [1234h+X]; etc.)<BR>
<BR>
<B>Rotate Left through Carry</B><BR>
<TABLE><TR><TD><PRE>  2A        nzc---  2   ROL A       Rotate Left Accumulator  RCL A
  26 nn     nzc---  5   ROL nn      Rotate Left Zero Page    RCL [nn]
  36 nn     nzc---  6   ROL nn,X    Rotate Left Zero Page,X  RCL [nn+X]
  2E nn nn  nzc---  6   ROL nnnn    Rotate Left Absolute     RCL [nnnn]
  3E nn nn  nzc---  7   ROL nnnn,X  Rotate Left Absolute,X   RCL [nnnn+X]
</TD></TR></TABLE>Nocash syntax: RCL op/reg (RCL A; RCL [12h]; RCL [1234h+X]; etc.)<BR>
<BR>
<B>Rotate Right through Carry</B><BR>
<TABLE><TR><TD><PRE>  6A        nzc---  2   ROR A       Rotate Right Accumulator RCR A
  66 nn     nzc---  5   ROR nn      Rotate Right Zero Page   RCR [nn]
  76 nn     nzc---  6   ROR nn,X    Rotate Right Zero Page,X RCR [nn+X]
  6E nn nn  nzc---  6   ROR nnnn    Rotate Right Absolute    RCR [nnnn]
  7E nn nn  nzc---  7   ROR nnnn,X  Rotate Right Absolute,X  RCR [nnnn+X]
</TD></TR></TABLE>Nocash syntax: RCR op/reg (RCR A; RCR [12h]; RCR [1234h+X]; etc.)<BR>
<BR>
Notes:<BR>
ROR instruction is available on MCS650X microprocessors after June, 1976.<BR>
ROL and ROL rotate an 8bit value through carry (rotates 9bits in total).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="cpujumpandcontrolinstructions"></A><FONT SIZE=+2>&nbsp;CPU Jump and Control Instructions</FONT></TD></TR></TABLE><BR>
<B>Normal Jumps</B><BR>
<TABLE><TR><TD><PRE>  4C nn nn  ------  3   JMP nnnn    Jump Absolute              PC=nnnn
  6C nn nn  ------  5   JMP (nnnn)  Jump Indirect              PC=WORD[nnnn]
  20 nn nn  ------  6   JSR nnnn    Jump and Save Return Addr. [S]=PC+2,PC=nnnn
  40        nzcidv  6   RTI         Return from BRK/IRQ/NMI    P=[S], PC=[S]
  60        ------  6   RTS         Return from Subroutine     PC=[S]+1
</TD></TR></TABLE>Nocash syntax: JMP nnnn; JMP [nnnn]; CALL nnnn (=JSR); RETI; RET (=RTS).<BR>
Note: RTI cannot modify the B-Flag or the unused flag.<BR>
Glitch: For JMP [nnnn] the operand word cannot cross page boundaries, ie.
JMP [03FFh] would fetch the MSB from [0300h] instead of [0400h]. Very
simple workaround would be to place a ALIGN 2 before the data word.<BR>
<BR>
<B>Conditional Branches (Branch on condition, to PC=PC+/-nn)</B><BR>
<TABLE><TR><TD><PRE>  10 dd     ------  2** BPL/JNS disp          ;N=0 (plus/positive)
  30 dd     ------  2** BMI/JS  disp          ;N=1 (minus/negative/signed)
  50 dd     ------  2** BVC/JNO disp          ;V=0 (no overflow)
  70 dd     ------  2** BVS/JO  disp          ;V=1 (overflow)
  90 dd     ------  2** BCC/BLT/JNC/JB  disp  ;C=0 (less/below/no carry)
  B0 dd     ------  2** BCS/BGE/JC/JAE  disp  ;C=1 (above/greater/equal/carry)
  D0 dd     ------  2** BNE/BZC/JNZ/JNE disp  ;Z=0 (not zero/not equal)
  F0 dd     ------  2** BEQ/BZS/JZ/JE   disp  ;Z=1 (zero/equal)
</TD></TR></TABLE>Nocash syntax: Jxx nnnn; Native syntax: Bxx nnnn.<BR>
** The execution time is 2 cycles if the condition is false (no branch
executed). Otherwise, 3 cycles if the destination is in the same memory
page, or 4 cycles if it crosses a page boundary (see below for exact info).<BR>
Note: After subtractions (SBC or CMP) carry=set indicates above-or-equal,
unlike as for 80x86 and Z80 CPUs.<BR>
<BR>
<B>Interrupts, Exceptions, Breakpoints</B><BR>
<TABLE><TR><TD><PRE>  00        ---1--  7   BRK   Force Break B=1 [S]=PC+1,[S]=P,I=1,PC=[FFFE]
  --        ---1--  ??  /IRQ  Interrupt   B=0 [S]=PC,[S]=P,I=1,PC=[FFFE]
  --        ---1--  ??  /NMI  NMI         B=0 [S]=PC,[S]=P,I=1,PC=[FFFA]
  --        ---1--  T+6 /RESET Reset      PC=[FFFC],I=1
</TD></TR></TABLE>Notes: IRQs can be disabled by setting the I-flag, a BRK command, a NMI,
and a /RESET signal cannot be masked by setting I.<BR>
BRK/IRQ/NMI first change the B-flag, then write P to stack, and then set
the I-flag, the D-flag is NOT changed and should be cleared by software.<BR>
The same vector is shared for BRK and IRQ, software can separate between
BRK and IRQ by examining the pushed B-flag only.<BR>
The RTI opcode can be used to return from BRK/IRQ/NMI, note that using the
return address from BRK skips one dummy/parameter byte following after the
BRK opcode.<BR>
Software or hardware must take care to acknowledge or reset /IRQ or /NMI
signals after processing it.<BR>
<TABLE><TR><TD><PRE>  IRQs are executed whenever "/IRQ=LOW AND I=0".
  NMIs are executed whenever "/NMI changes from HIGH to LOW".
</TD></TR></TABLE>If /IRQ is kept LOW then same (old) interrupt is executed again as soon as
setting I=0. If /NMI is kept LOW then no further NMIs can be executed.<BR>
<BR>
<B>CPU Control</B><BR>
<TABLE><TR><TD><PRE>  18        --0---  2   CLC         Clear carry flag            C=0
  58        ---0--  2   CLI         Clear interrupt disable bit I=0
  D8        ----0-  2   CLD         Clear decimal mode          D=0
  B8        -----0  2   CLV         Clear overflow flag         V=0
  38        --1---  2   SEC         Set carry flag              C=1
  78        ---1--  2   SEI         Set interrupt disable bit   I=1
  F8        ----1-  2   SED         Set decimal mode            D=1
</TD></TR></TABLE>Nocash Syntax: CLC; EI (=CLI); CLD, CLV; STC; DI (=STI); STD.<BR>
<BR>
<B>No Operation</B><BR>
<TABLE><TR><TD><PRE>  EA        ------  2   NOP         No operation                No operation
</TD></TR></TABLE><BR>
<B>Conditional Branch Page Crossing</B><BR>
The branch opcode with parameter takes up two bytes, causing the PC to get
incremented twice (PC=PC+2), without any extra boundary cycle. The signed
parameter is then added to the PC (PC+disp), the extra clock cycle occurs
if the addition crosses a page boundary (next or previous 100h-page).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="cpuillegalopcodes"></A><FONT SIZE=+2>&nbsp;CPU Illegal Opcodes</FONT></TD></TR></TABLE><BR>
<B>SAX and LAX</B><BR>
<TABLE><TR><TD><PRE>  87 nn     ------  3   SAX nn      STA+STX  [nn]=A AND X
  97 nn     ------  4   SAX nn,Y    STA+STX  [nn+Y]=A AND X
  8F nn nn  ------  4   SAX nnnn    STA+STX  [nnnn]=A AND X
  83 nn     ------  6   SAX (nn,X)  STA+STX  [WORD[nn+X]]=A AND X
  A7 nn     nz----  3   LAX nn      LDA+LDX  A,X=[nn]
  B7 nn     nz----  4   LAX nn,Y    LDA+LDX  A,X=[nn+Y]
  AF nn nn  nz----  4   LAX nnnn    LDA+LDX  A,X=[nnnn]
  A3 nn     nz----  6   LAX (nn,X)  LDA+LDX  A,X=[WORD[nn+X]]
  B3 nn     nz----  5*  LAX (nn),Y  LDA+LDX  A,X=[WORD[nn]+Y]
</TD></TR></TABLE>For SAX, both A and X are output to databus, LOW-bits are stronger than
HIGH-bits, resulting in a "forceful" AND operation.<BR>
For LAX, the same value is written to both A and X.<BR>
<BR>
<B>Combined ALU-Opcodes</B><BR>
Opcode high-bits, flags, commands:<BR>
<TABLE><TR><TD><PRE>  00+yy        nzc---  SLO op   ASL+ORA   op=op SHL 1 // A=A OR op
  20+yy        nzc---  RLA op   ROL+AND   op=op RCL 1 // A=A AND op
  40+yy        nzc---  SRE op   LSR+EOR   op=op SHR 1 // A=A XOR op
  60+yy        nzc--v  RRA op   ROR+ADC   op=op RCR 1 // A=A+op+cy
  C0+yy        nzc---  DCP op   DEC+CMP   op=op-1     // A-op
  E0+yy        nzc--v  ISC op   INC+SBC   op=op+1     // A=A-op-(1-cy)
</TD></TR></TABLE>Opcode low-bits, clock cycles, operands:<BR>
<TABLE><TR><TD><PRE>  07+xx nn        5    nn       [nn]
  17+xx nn        6    nn,X     [nn+X]
  03+xx nn        8    (nn,X)   [WORD[nn+X]]
  13+xx nn        8    (nn),Y   [WORD[nn]+Y]
  0F+xx nn nn     6    nnnn     [nnnn]
  1F+xx nn nn     7    nnnn,X   [nnnn+X]
  1B+xx nn nn     7    nnnn,Y   [nnnn+Y]
</TD></TR></TABLE><BR>
<B>Other Illegal Opcodes</B><BR>
<TABLE><TR><TD><PRE>  0B nn     nzc---  2  ANC #nn          AND+ASL  A=A AND nn, C=N ;bit7 to carry
  2B nn     nzc---  2  ANC #nn          AND+ROL  A=A AND nn, C=N ;same as above
  4B nn     nzc---  2  ALR #nn          AND+LSR  A=(A AND nn) SHR 1
  6B nn     nzc--v  2  ARR #nn          AND+ROR  A=(A AND nn), V=Overflow(A+A),
                                                 A=A/2+C*80h, C=A.Bit6
  CB nn     nzc---  2  AXS #nn          CMP+DEX  X=(X AND A)-nn
  EB nn     nzc--v  2  SBC #nn          SBC+NOP  A=A-nn         cy?
  BB nn nn  nz----  4* LAS nnnn,Y       LDA+TSX  A,X,S = [nnnn+Y] AND S
</TD></TR></TABLE><BR>
<B>NUL/NOP and KIL/JAM/HLT</B><BR>
<TABLE><TR><TD><PRE>  xx        ------  2   NOP        (xx=1A,3A,5A,7A,DA,FA)
  xx nn     ------  2   NOP #nn    (xx=80,82,89,C2,E2)
  xx nn     ------  3   NOP nn     (xx=04,44,64)
  xx nn     ------  4   NOP nn,X   (xx=14,34,54,74,D4,F4)
  xx nn nn  ------  4   NOP nnnn   (xx=0C)
  xx nn nn  ------  4*  NOP nnnn,X (xx=1C,3C,5C,7C,DC,FC)
  xx        ------  -   KIL        (xx=02,12,22,32,42,52,62,72,92,B2,D2,F2)
</TD></TR></TABLE>NOP doesn't change any registers or flags, the operand (if any) is
fetched, may be useful for delays, patches, or for read-sensitive I/O
ports. KIL halts the CPU, the data bus will be set to #$FF, KIL can be
suspended by /RESET signal (not sure if also by /IRQ or /NMI ???).<BR>
<BR>
<B>Unstable Illegal Opcodes</B><BR>
<TABLE><TR><TD><PRE>  8B nn     nz----  2  XAA #nn    ((2)) TXA+AND  A=X AND nn
  AB nn     nz----  2  LAX #nn    ((2)) LDA+TAX  A,X=nn
  BF nn nn  nz----  4* LAX nnnn,X       LDA+LDX  A,X=[nnnn+X]
  93 nn     ------  6  AHX (nn),Y ((1))          [WORD[nn]+Y] = A AND X AND H
  9F nn nn  ------  5  AHX nnnn,Y ((1))          [nnnn+Y] = A AND X AND H
  9C nn nn  ------  5  SHY nnnn,X ((1))          [nnnn+X] = Y AND H
  9E nn nn  ------  5  SHX nnnn,Y ((1))          [nnnn+Y] = X AND H
  9B nn nn  ------  5  TAS nnnn,Y ((1)) STA+TXS  S=A AND X  // [nnnn+Y]=S AND H
</TD></TR></TABLE>note to XAA: DO NOT USE!!! Highly unstable!!!<BR>
note to LAX: DO NOT USE!!! On my C128, this opcode is stable, but on my C64-II<BR>
it loses bits so that the operation looks like this: ORA #? AND #{imm} TAX.<BR>
note to AXS: performs CMP and DEX at the same time, so that the MINUS sets<BR>
the flag like CMP, not SBC.<BR>
Combinations of STA/STX/STY:<BR>
<TABLE><TR><TD><PRE> AHX {adr} = stores A&X&H into {adr}
 SHX {adr} = stores X&H into {adr}
 SHY {adr} = stores Y&H into {adr}
</TD></TR></TABLE>note: sometimes the &H drops off. Also page boundary crossing will not work as<BR>
expected (the bank where the value is stored may be equal to the value stored).<BR>
["H" probably meant to be the MSB aka Highbyte of the 16bit memory address?]<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="cpuassemblerdirectivessyntax"></A><FONT SIZE=+2>&nbsp;CPU Assembler Directives/Syntax</FONT></TD></TR></TABLE><BR>
Below are some common 65XX assembler directives, and the corresponding
expressions in 80XX-style language.<BR>
<BR>
<TABLE><TR><TD><PRE><B>  65XX-style    80XX-style         Expl.</B>
  .native       .nocash            select native or nocash syntax
  *=$c100       org 0c100h         sets the assumed origin in memory
  *=*+8         org $+8            increments origin, does NOT produce data
  label         label:             sets a label equal to the current address
  label=$dc00   label equ 0dc00h   assigns a value or address to label
  .by $00       db 00h             defines a (list of) byte(s) in memory
  .byt $00      defb 00h           same as .by and db
  .wd $0000     dw 0000h           defines a (list of) word(s) in memory
  .end          end                indicates end of source code file
  |nn           [|nn]              force 16bit "00NN" instead 8bit "NN"
  #&lt;nnnn        nnnn AND 0FFh      isolate lower 8bits of 16bit value
  #&gt;nnnn        nnnn DIV 100h      isolate upper 8bits of 16bit value
</TD></TR></TABLE><BR>
<B>Special Directives</B><BR>
<TABLE><TR><TD><PRE>  .65xx       Select 6502 Instruction Set
  .nes        Create NES ROM-Image with .NES extension
  .c64_prg    Create C64 file with .PRG extension/stub/fixed entry
  .c64_p00    Create C64 file with .P00 extension/stub/fixed entry/header
  .vic20_prg  Create VIC20/C64 file with .PRG extension/stub/relocated entry
  end entry   End of Source, the parameter specifies the entrypoint
</TD></TR></TABLE>The C64 files contain Basic Stub "10 SYS&lt;entry&gt;" with default ORG 80Eh.<BR>
<BR>
<B>VIC20 Stub</B><BR>
The VIC20 Stub is "10 SYSPEEK(44)*256+&lt;entry&gt;" with default ORG 1218h, this
relocates the entryoint relative to the LOAD address (for C64: 818h, for
VIC20: 1018h (Unexpanded), 0418h (3K Expanded), 1218h (8K and more
Expansion). It does NOT relocate absolute addresses in the program, if the
program wishes to run at a specific memory location, then it must de-relocate
itself from the LOAD address to the desired address.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="cpuglitches"></A><FONT SIZE=+2>&nbsp;CPU Glitches</FONT></TD></TR></TABLE><BR>
<B>Dummy Read Cycles at Page-Wraps</B><BR>
Dummy reads occur when reads from [nnnn+X] or [nnnn+Y] or [WORD[nn]+Y] are
crossing page boundaries, this applies only to raw read-opcodes, not for
write or read-and-modify opcodes (ie. only for opcodes that include an extra
clock cycle on page boundaries, such as LDA, CMP, etc.)<BR>
For above reads, the CPU adds the index register to the lower 8bits of the
16bit memory address, and does then read from the resulting memory address,
if the addition caused a carry-out, then an extra clock cycle is used to
increment the upper 8bits of the address, and to read from the correct memory
location. For example, a read from [1280h+X] with X=C0h produces a dummy read
from [1240h], followed by the actual read from [1340h].<BR>
Dummy reads cause no problems with normal ROM or RAM, but may cause problems
with read-sensitive I/O ports (eg. IRQ flags that are automatically cleared
after reading, or data-registers that are automatically incrementing
accociated memory pointers, etc.)<BR>
<BR>
<B>Dummy Write Cycles in Read-Modify-Opcodes</B><BR>
Dummy writes occur in all read-modify opcodes, ie. all INC, DEC, Shift,
Rotate opcodes with memory operands. The opcodes consist of three memory
accesses: read original value, write dummy value, write result value.<BR>
Dummy writes cause no problems with normal RAM, but may cause problems (or
may be useful) with write-sensitive I/O ports (eg. IRQ flags that are cleared
by writing certain values, or data-registers that are automatically
incrementing accociated memory pointers, etc.)<BR>
On the C64 and C16, the written dummy value appears to be equal to the
original value, a couple of programs are using this to acknowledge IRQs.<BR>
On the NES, the dummy value appears to be equal to the result value, though
more or less unstable ANDed with a random number. Presumably 00h is output
during the first half of the write cycle, and the result only during the
second half, not leaving enough time to raise all bits from LOW to high.
Also, dummy writes to [2007h] aren't always recognized (ie. the VRAM address
register isn't always incremented twice), presumably because the PPU isn't
fast enough to realize two write-signals immediately after each other, that
maybe because it is attempting to synchronize CPU bus writes with the PPU
bus.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="cputhe65xxfamily"></A><FONT SIZE=+2>&nbsp;CPU The 65XX Family</FONT></TD></TR></TABLE><BR>
Different versions of the 6502:<BR>
<BR>
All of these processors are the same concerning the software-side:<BR>
<TABLE><TR><TD><PRE> 6501   Some sort of 6502 prototype
 6502   Used in the CBM floppies and some other 8 bit computers.
 6507   Used in Atari 2600, 28pins (only 13 address lines, no /IRQ, no /NMI).
 6510   Used in C64, with built-in 6bit I/O port.
 7501   Used in C16,C116,Plus/4, with built-in 7bit I/O Port, without /NMI pin.
 8500   Used in C64-II, with different pin-outs.
 8501   Same as 7501
 8502   Used in C128s.
</TD></TR></TABLE><BR>
Some processors of the family which are not 100% compatible:<BR>
<TABLE><TR><TD><PRE> 65C02  Extension of the 6502, used in the C16, C116 and the Plus/4 computers?
 65SC02 Small version of the 65C02 which lost a few opcodes again.
 65CE02 Extension of the 65C02, used in the C65.
 65816  Extended 6502 with new opcodes and 16 bit operation modes.
 2A03   Nintendo NES/Famicom, modified 6502 with built-in sound controller.
</TD></TR></TABLE><BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="cpulocalusage"></A><FONT SIZE=+2>&nbsp;CPU Local Usage</FONT></TD></TR></TABLE><BR>
<B>Atari 2600 - CPU 6507</B><BR>
The 6507 is a 6502-compatible CPU squeezed into a DIL-28 package, it's having
only 8K address space, and doesn't have any IRQ or NMI inputs.<BR>
Clocked at 1.193182 MHz (NTSC), 1.182298 MHz (PAL).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="hardwaresoldering"></A><FONT SIZE=+2>&nbsp;Hardware / Soldering</FONT></TD></TR></TABLE><BR>
<B>Hardware Tuning</B><BR>
<A HREF="#nocashsramcircuit">Nocash SRAM Circuit</A><BR>
<A HREF="#usingapcpowersupply">Using a PC Power Supply</A><BR>
<BR>
<B>Cartridge Slot and Controller Ports</B><BR>
<A HREF="#controllersexternalportpinouts">Controllers: External Port Pin-Outs</A><BR>
<A HREF="#cartpinouts">Cart Pin-Outs</A><BR>
<BR>
<B>Mainboard - CPU, PIA, TIA</B><BR>
<A HREF="#chipsetpinouts">Chipset Pin-Outs</A><BR>
<BR>
<B>Other Connectors</B><BR>
- TV: One Cinch Socket (Video/Audio TV Signal)<BR>
- Power: 9V DC, 500mA (internally converted to 5V DC)<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="nocashsramcircuit"></A><FONT SIZE=+2>&nbsp;Nocash SRAM Circuit</FONT></TD></TR></TABLE><BR>
<B>Nocash SRAM Circuit</B><BR>
This circuit has been developed while testing no$2k6, it wired directly to
the Atari mainboard, and allows to upload ROM-images from PC to Atari via
function in no$2k6 utility menu. Features:<BR>
<TABLE><TR><TD><PRE> - one-directional 4bit highspeed upload (when joystick is not moved)
 - bi-directional 1bit transmission for upload/download/debug terminal
 - works with external carts (if parallel cable disconnected or all high)
 - upload with automatic reset (autostart)
 - works with any older/newer one/two-directional PC parallel port
 - supports almost all existing cartridge types (except eight games)
</TD></TR></TABLE>Only a few exotic cartridges (eight games) are not supported: JSR banking
(Decathln), 256 bytes RAM expansion (Mtnking, Omegarac, Tunlrunr), Port
FFEX Nx2K banking (Bnj, Burgtime, He_man), and the sequential memory
controller (Pitfall2).<BR>
<BR>
<B>Step 1 - Basic Connection (raw 1K,2K,4K unbanked ROM) (for 348 games)</B><BR>
<TABLE><TR><TD><PRE>                _____________                _____________
        D0-7 --|D0-7         |       D0-7 --|D0-7         |
   A0-6,8-10 --|A06,8-10     |  A0-6,8-10 --|A0-6,8-10    |
      XA7,11 --|A7,11        |  XA7,11-14 --|A7,11-14     |
         VCC --|A12-15 EPROM |       /WRS --|/WE   SRAM   |
       /MREQ --|/CS    64Kx8 |      /MREQ --|/CS   32Kx8  |
  /PROM.DTA3 --|/OE   27C512 | /SRAM.DTA2 --|/OE   62C256 |
               |_____________|              |_____________|
</TD></TR></TABLE><BR>
<TABLE><TR><TD><PRE>  XA7         --------- A7               /RES.DTA4   ---|&lt;|--- /RES,TP2,C27(+)
  XA11        --------- A11              /PROM.DTA3  --[10K]-- VCC
  R/W         --------- /WRS             /SRAM.DTA2  --[10K]-- VCC
  LPT.DTA0    --------- SWCHB.5,PIA.18   CART.DTA5   --[10K]-- VCC
  LPT.DTA1    --------- SWCHB.4,PIA.19   XA12        --[10K]-- VCC
  LPT.BUSY    --------- SWCHB.2,PIA.22   XA13        --[10K]-- VCC
  LPT./STB    --------- SWCHA.0,PIA.8    XA14        --[10K]-- VCC
  LPT./AUTOLF --------- SWCHA.2,PIA.10                  ____
  LPT./INIT   --------- SWCHA.4,PIA.12          A12  --|AND \__ CS,SLOT.18
  LPT./SELECT --------- SWCHA.6,PIA.14    CART.DTA5  --|____/
  LPT.GND     --------- GND                     A12  --|NAND\__ /MREQ
  CS,SLOT.18  --/cut/-- A12                    PHI2  --|____/
</TD></TR></TABLE><BR>
<B>Step 2 - Port 3Fh (Nx2K ROM) (for 6 games & control bits for next step)</B><BR>
<TABLE><TR><TD><PRE>                               ____               _______
  A11 --/cut/--- XA11   A6  --|    |-------------|LE     |
  GND ---------- 1K     A7  --|NOR |        D0 --|D0   Q0|-|&lt;|- XA11
  LPT.DTA6 ----- 3F     A12 --|    |        D1 --|D1   Q1|-|&lt;|- XA12
            ____        R/W --|    |        D2 --|D2   Q2|-|&lt;|- XA13
  3F    ___|INV \_____________|    |        D3 --|D3   Q3|-|&lt;|- XA14
           |____/    /3F      |____|        D4 --|D4   Q4|-- 1K
  A11   ---|NOR |   ____                    D5 --|D5   Q5|-- 4K
  3F    ---|    |__|INV \--|&lt;|--XA11        D6 --|D6   Q6|-- /16K
  1K    ---|    |  |____/            ____   D7 --|D7   Q7|-- /32K
  GND   ---|    |              3F --|AND \_______|/OE    |
  GND   ---|____|             A11 --|____/       |_______| 74373
  XA11 --[10K]-- VCC         XA10 --[10K]-- VCC      1K --[10K]-- VCC
</TD></TR></TABLE><BR>
<B>Step 3 - Port FFFXh (Nx4K ROM) (for ca. 160 games)</B><BR>
<TABLE><TR><TD><PRE>         ____             ____                              _________
  PHI2 -|    |   A2 -----|NAND\_ ____           ____   4K -|/CE1 /OE1|-- XRAM
  A5 ---|    |   /32K ---|____/ |XOR \_________|    |  3F -|/CE2 /OE2|-- GND
  A6 ---|NAND|   A1 -----|NAND\_|____/ /GOODA2 |    |______|CLK   RES|-- GND
  A7 ---|    |   16K ----|____/         _______|NOR |      |  74173  |
  A8 ---|    |   A2 -----|NAND\_ ____   GND    |    |  A0 -|D0     Q0|-|&lt;|-XA12
  A9 ---|    |   16K32K -|____/ |XOR \_________|    |  A1 -|D1     Q1|-|&lt;|-XA13
  A10 --|    |_  A3 ------------|____/ /GOODA3 |    |  A2 -|D2     Q2|-|&lt;|-XA14
  A11 --|____| | GND --- XRAM  ________________|    |  NC -|D3     Q3|-- NC
         ____  |______________|  ____  /GOODFF |    |      |_________|
  /16K -|XOR \___            ___|INV \_________|    |  /16K --|XOR \__ 16K
  /32K -|____/   16K32K    A4   |____/ /GOODA4 |____|   VCC --|____/
</TD></TR></TABLE><BR>
<B>Step 4 - XRAM (128 Bytes Expansion RAM) (for 17 games) (and Write Protect)</B><BR>
<TABLE><TR><TD><PRE>                 ____                                              ____
  A8         ---|    |-- XRAM    GND --/cut/-- XRAM         XRAM -|OR  \__ XA7
  A9         ---|NOR |            A7 --/cut/-- XA7          A7  --|____/
  A10        ---|    |           R/W --/cut/-- /WRS   ____  R/W --|OR  \__ /WRS
  A11        ---|    |   /XRAM.DTA7 -----------------|AND \_______|____/
  /XRAM.DTA7 ---|____|   /3F        -----------------|____/ WPROT
</TD></TR></TABLE><BR>
<B>Step 5 - Port FFXXh (Nx1K ROM) (for 13 games)</B><BR>
<TABLE><TR><TD><PRE>            __________                                           ____
  A0..2 ---|D0-2  Q0-2|--- XA10..12   A10 --/cut/-- XA10   1K --|OR  \-|&lt;|-XA10
  A12 -----|D3      Q3|--- NC         GND --/cut/-- 1K    A10 --|____/
  A3 ------|WA0    RA0|--- A10               ____          3F __|INV \-|&lt;|- 1K
  A4 ------|WA1    RA1|--- A11  ____ _______/AND |--- A10       |____/
  /GOODFF -|/WR    /RD|________/OR  |       \____|--- A11  1K __|INV \_____ /1K
           |__________| 74170  \____|__/1K                      |____/
</TD></TR></TABLE><BR>
<B>Notes</B><BR>
The Eprom socket can be soldered directly on top of the SRAM (only Pins 1,
2, 22, 26, and 27 need different connection).<BR>
Implement the separate steps in incrementing order, steps 2 and up are
optional, the device should be fully functional after completion of each
step, do not attempt to implement all steps at once, establish 1-2 days
per step.<BR>
<BR>
<B>Parts List</B><BR>
<TABLE><TR><TD><PRE>  1  27C512 EPROM (or EEPROM, or FLASH, or other size, min 1KByte)
  1  62C256 Static RAM (32KBytes or bigger)
  1  74LS04 Hex Inverter
  1  74LS08 Quad 2-input AND gate
  1  74LS30 Single 8-input NAND gate
  1  74LS32 Quad 2-input OR gate
  1  74LS86 Quad 2-input XOR gate
  1  74LS170 4x4 Register File open collector
  1  74LS173 4-bit 3-state flip-flop with clock enable
  2  74LS260 Dual 5-input NOR gate
  1  74LS374 8-bit 3-state flip-flop
  9  10K Ohm Resistors
 11  1N4148 diodes (for /Reset signal, and ANDed "XAnn" and "1K" outputs)
  1  Centronics socket 36pin female (and standard printer cable)
</TD></TR></TABLE>Plus socket(s) for EPROM (and any other chips), 100nF capacitors for all
chips, wire, board, solder, tools, eprom burner.<BR>
Caution: 74LS260 outputs are at Pin 5 & 6 (unlike some internet-specs say)<BR>
<BR>
<B>BIOS EPROM</B><BR>
<TABLE><TR><TD><PRE>  0000 20 4A FC 9D FC 34 20 4C FC FF FC 26 20 25 FD 85
  0010 85 20 25 FD 85 86 A9 00 85 80 A9 F0 85 81 20 87
  0020 00 20 3F FC 4C 30 FC 20 87 00 20 3F FC 4C 30 FC
  0030 20 4A FC D1 FC 2E 20 4C FC 25 FD 27 4C 87 00 A5
  0040 82 20 FF FC A5 83 20 FF FC 60 A0 87 20 6C FC 85
  0050 80 20 6C FC 85 81 20 6C FC 85 84 98 AA A0 00 B1
  0060 80 95 00 C8 E8 C4 84 D0 F6 8A A8 60 BA F6 03 D0
  0070 02 F6 04 A1 03 60 A0 00 84 80 20 AE 00 85 3F 20
  0080 AE 00 85 81 0A F0 15 20 AE 00 91 80 18 65 82 85
  0090 82 A9 00 65 83 85 83 C8 D0 ED F0 DE 60 20 BB 00
  00A0 A6 85 DD 00 FF A0 00 B1 80 48 20 BB 00 68 18 65
  00B0 82 85 82 A9 00 65 83 85 83 E6 80 D0 E3 E6 81 D0
  00C0 DF A9 F0 85 81 A5 85 E6 85 C5 86 D0 D3 20 BB 00
  00D0 60 20 B5 00 85 3F 20 B5 00 A2 58 86 49 8D 97 00
  00E0 CD 00 FF A9 0F 85 3F A9 FF 8D 97 02 8D 80 02 8D
  00F0 82 02 A9 00 85 81 8D 81 02 8D 83 02 6C FC FF 85
  0100 84 A0 04 A9 10 06 84 69 03 8D 82 02 A9 10 2C 82
  0110 02 D0 FB 06 84 69 03 8D 82 02 A9 10 2C 82 02 F0
  0120 FB 88 D0 E1 60 A9 01 85 84 A9 10 2C 82 02 D0 FB
  0130 0A 2D 82 02 C9 20 26 84 A9 10 2C 82 02 F0 FB 0A
  0140 2D 82 02 C9 20 26 84 90 E0 A5 84 60 A9 10 2C 82
  0150 02 D0 FB 0E 80 02 2C 82 02 F0 FB AD 80 02 60 A2
  0160 00 BD 99 FD 20 FF FC E8 BD 99 FD D0 F4 A2 00 20
  0170 25 FD DD AA FD D0 FE E8 E0 08 D0 F3 A9 2B 20 FF
  0180 FC A2 00 A0 2B 20 4C FD DD AA FD F0 02 A0 2D E8
  0190 E0 08 D0 F1 98 20 FF FC 60 4E 4F 24 32 4B 36 20
  01A0 42 49 4F 53 20 56 31 2E 31 00 00 FF 55 AA 0F F0
  01B0 3C C3 20 25 FD 85 3F 20 25 FD CD F7 FF 20 25 FD
  01C0 85 3F 60 78 D8 A9 00 AA 95 00 9A E8 D0 FA A9 0E
  01D0 85 3F A9 04 8D 83 02 A9 AA 8D 81 02 A2 28 86 49
  01E0 20 5F FD 20 B2 FD 20 25 FD C9 31 F0 0B C9 34 F0
  01F0 1A C9 44 F0 25 4C F5 FD A2 00 86 49 20 4A FC 76
  0200 FC 27 20 4C FC 25 FD 27 4C 27 FC 20 4A FC 76 FC
  0210 27 20 4C FC 4C FD 13 4C 27 FC 4C 00 FC FF FF FF
  0220 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
  .... FF FF FF ............................. FF FF FF
  03F0 FF FF FF FF FF FF FF FF FF FF FF FF C3 FD 00 00
</TD></TR></TABLE>To be placed to highest memory location, eg. FC00h-FFFFh for 64K chips.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="usingapcpowersupply"></A><FONT SIZE=+2>&nbsp;Using a PC Power Supply</FONT></TD></TR></TABLE><BR>
When using a PC (or other computer) to develop Atari games it might be
recommended to connect the console directly to the PC's power supply,
without having to use the external 9V power supply.<BR>
<BR>
<B>Using +5V DC Power Supply</B><BR>
Connect +5V (red floppy cable) directly to the 7805 voltage regulator's
5V output (not to the 9V input). Connect GND (black floppy cable) to
middle 7805 pin (not required if centronics cable is connected). Most of
the console works fine at 5V, but a few things still need to get
modified to get it working at raw 5V only:<BR>
Move the power switch into 5V line (so that 9V are always on, and that 5V
can be switched on and off). Replace the 750 Ohm LED resistor (R57) by 390
Ohm, and connect it to 5V instead of 9V. And, most important, connect
color adjust potientometer (R9) to 5V instead of 6.2V, and re-adjust it so
that it outputs approximately 3.38V (PAL) at the middle pin.<BR>
That's it. It's now everything working at 5V internally - and would still
work alternately with 9V external supply.<BR>
<BR>
<B>Using +12V DC Power Supply</B><BR>
Alternately, +12V (yellow floppy cable) could be connected directly to the
9V input without any console modifications.<BR>
Drawbacks would be that the 7805 voltage converter would be producing more
heat, and that some consoles are using a '3.5mm headphone socket' as power
input - which would produce a shortcut (and shutdown the PC power supply)
when inserting/removing the plug.<BR>
Note: An external 7809 would solve that problems, it'd split the heat to
the 7809 and 7805, and it'd provide a more or less reliable protection
against shortcuts (at least for short periodes, the 7809 would get very
hot if the plug is stuck in 'half inserted' position).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="chipsetpinouts"></A><FONT SIZE=+2>&nbsp;Chipset Pin-Outs</FONT></TD></TR></TABLE><BR>
<B>PIA</B><BR>
<TABLE><TR><TD><PRE>  33..26   D0..D7
  7..2,40  A0..A6
  35       R/W
  25       IRQ (NC)
  36       /RS (A9)
  37       /CS2 (A12)
  38       CS1 (A7)
  39       PHI2
  34       /RES
  8..15    PA0..PA7 (UDLR2, UDLR1)
  1,20     VCC,GND
  16..24   PB7..PB0 (DIF1,DIF0,NC,NC,COLOR,SELECT,RESET)
</TD></TR></TABLE><BR>
<B>CPU 6507</B><BR>
<TABLE><TR><TD><PRE>  25..28   D0..D7
  4,2      VCC,GND
  5..17    A0..A12
  1,3,26   /RES,RDY,R/W
  27,28    PHI0,PHI2
</TD></TR></TABLE><BR>
<B>TIA PAL</B><BR>
<TABLE><TR><TD><PRE>  14..19,33..34  D0..D7
  32..27         A0..A5
  21,24          /CS1 (A7), /CS2 (A12)
  3,25,4,26,11   RDY,R/W,PHI0,PHI2,OSC
  40..37,36,35   P0..P3 (POT0..3), T0..T1 (BUTTON1,2)
  7,5,6          LUM0,LUM1,LUM3
  2,9,10,13      CSYN, COLOR, CADJ (+3.4V), AUD
  12,8           PALS,PALI
  20,23,22,1     VCC,VCC,GND,GND
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="links"></A><FONT SIZE=+2>&nbsp;Links</FONT></TD></TR></TABLE></TD></TR></TABLE><BR>
<B>AtariAge - Atari 2600 ROMs</B><BR>
About 500 games (ROM images) for the Atari 2600, about 2MB zipped.<BR>
<TABLE><TR><TD><PRE>  http://www.atariage.com/system_items.html?SystemID=2600&ItemTypeID=ROM
</TD></TR></TABLE>The webpage also includes a nice FAQ, very useful schematics, and various
other info. The separate pages are badly generated bloated html, loading
VERY slowly, and likely to crash your browser.<BR>
<BR>
<B>Stella Programmer's Guide</B><BR>
Official specs for Atari 2600, TIA and PIA chips (but lacks information
about CPU and ROM), by Steve Wright 12/03/79, reconstructed by Charles
Sinnett 6/11/93.<BR>
<TABLE><TR><TD><PRE>  http://alienbill.com/vgames/guide/docs/stella.html
</TD></TR></TABLE>This document is a matter of slightly increasing information, each
chapter repeats the information from the previous chapter and reveals
some additional details.<BR>
<BR>
<B>65xx processor series opcodes</B><BR>
Very nice summary of documented and undocumented 65XX opcodes.<BR>
<TABLE><TR><TD><PRE>  http://oxyron.net/graham/opcodes.html
</TD></TR></TABLE><BR>
<B>nocash 2K6 specs</B><BR>
This document (or newer updates), in TXT and HTM format.<BR>
<TABLE><TR><TD><PRE>  http://nocash.emubase.de/2k6specs.txt
  http://nocash.emubase.de/2k6specs.htm
</TD></TR></TABLE>Atari 2600 Programming Specs. Describes TIA and PIA I/O ports, CPU,
memory, cartridges, joysticks, paddles, etc.<BR>
<BR>
</BODY></HTML>
